o
    )j~                    @   s  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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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# d d	l$m%Z% d dl&Z&d dl'Z'd d
l'm(Z( d dl)m*Z*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1m2Z2m3Z3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZDmEZEmFZFmGZGmHZHmIZImJZJmKZKmLZLmMZMmNZNmOZOmPZPmQZQmRZRmSZSmTZTmUZUmVZVmWZWmXZXmYZYmZZZm[Z[m\Z\m]Z]m^Z^ d dl_m`Z`maZambZbmcZcmdZdmeZemfZfmgZgmhZhmiZi d dljmkZk d dllmmZmmnZn d dlompZp d dlqmrZr d dlsmtZt d dlumvZvmwZwmxZxmyZy d dlzm{Z{ d dl|m}Z}m~Z~mZmZmZmZmZ d dlmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZmZ d dlmZmZmZ d dlmZ d dlmZmZmZmZmZmZmZmZ e ZdedefddZG d d! d!ZG d"d# d#ZG d$d% d%ZG d&d' d'ZdS )(    N)defaultdict)ThreadPoolExecutor)
HTTPStatus)	CookieJar)
expanduserPath)	AnyBinaryIODictIterableListLiteralOptionalTupleUnion)	urlencode)Session)HTTPAdapterRetry)	HTTPErrortqdm).API_HTTP_CLIENT_MAX_RETRIESAPI_HTTP_CLIENT_TIMEOUTAPI_RESPONSE_FIELD_DATAAPI_RESPONSE_FIELD_EMAIL#API_RESPONSE_FIELD_GIT_ACCESS_TOKENAPI_RESPONSE_FIELD_MESSAGEAPI_RESPONSE_FIELD_USERNAMEDEFAULT_MAX_WORKERSDEFAULT_MODELSCOPE_INTL_DOMAINMODELSCOPE_CLOUD_ENVIRONMENTMODELSCOPE_CLOUD_USERNAMEMODELSCOPE_CREDENTIALS_PATHMODELSCOPE_DOMAINMODELSCOPE_PREFER_AI_SITEMODELSCOPE_REQUEST_IDMODELSCOPE_URL_SCHEMEONE_YEAR_SECONDSREQUESTS_API_HTTP_METHODTEMPORARY_FOLDER_NAMEUPLOAD_ADAPTIVE_BATCH_SIZEUPLOAD_BLOB_MAX_RETRIESUPLOAD_BLOB_RETRY_BACKOFFUPLOAD_BLOB_RETRY_MAX_WAITUPLOAD_BLOB_TIMEOUT"UPLOAD_BLOB_TQDM_DISABLE_THRESHOLDUPLOAD_COMMIT_BATCH_SIZEUPLOAD_FAILED_FILE_MAX_RETRIESUPLOAD_MAX_FILE_COUNTUPLOAD_MAX_FILE_COUNT_IN_DIRUPLOAD_MAX_FILE_SIZE#UPLOAD_NORMAL_FILE_SIZE_TOTAL_LIMIT!UPLOAD_REACT_BACKOFF_MAX_EXPONENTUPLOAD_REACT_ENABLEDUPLOAD_REACT_MAX_DELAYUPLOAD_REACT_ROUND2_BASE_DELAYUPLOAD_REACT_ROUND3_FILE_DELAYUPLOAD_RETRY_ALLOWED_METHODS$UPLOAD_SIZE_THRESHOLD_TO_ENFORCE_LFSUPLOAD_USE_CACHEUPLOAD_VALIDATE_BLOB_BATCH_SIZEVALID_SORT_KEYSDatasetVisibilityLicensesModelVisibility
VisibilityVisibilityMap)
InvalidParameterNotExistErrorNotLoginExceptionRequestErrordatahub_raise_on_errorhandle_http_post_errorhandle_http_responseis_okraise_for_http_statusraise_on_error)GitCommandWrapper)DatasetInfo	ModelInfo
Repository)UPLOAD_HASH_CACHE_FILE)BatchTracker)_LEGACY_PROGRESS_FILENullTrackerUploadTrackerclassify_error)	AigcModel)add_content_to_file
get_domainget_endpointget_readable_folder_sizeget_release_datetimeis_env_truemodel_id_to_group_owner_name)DEFAULT_DATASET_REVISIONDEFAULT_MODEL_REVISIONDEFAULT_REPOSITORY_REVISIONMASTER_MODEL_BRANCHMETA_FILES_FORMATREPO_TYPE_DATASETREPO_TYPE_MODELREPO_TYPE_SUPPORTConfigFieldsDatasetFormationsDatasetMetaFormatsDownloadChannelDownloadMode
Frameworks	ModelFileTasksVirgoDatasetConfig)compute_file_hashget_file_sizeis_relative_path)
get_logger)DATASET_LFS_SUFFIXDEFAULT_IGNORE_PATTERNSMODEL_LFS_SUFFIXCommitHistoryResponse
CommitInfoCommitOperationCommitOperationAdd	RepoUtilstotal_filesreturnc                 C   sN   | dkrdS | dkr| S | dkrt d| d S | dkr%t dtd| d S d	S )
a  Calculate optimal commit batch size based on total file count.

    Adaptive strategy ensures batch granularity scales with workload:
    - Very few files (1-10): no splitting, single batch
    - Few files (11-100): ~10 batches for failure isolation
    - Medium (101-10K): 64-256 files per batch
    - Large (>10K): 512 files per batch to limit commit frequency

    Args:
        total_files: Total number of files (including checkpoint-skipped).

    Returns:
        Recommended batch size (>= 1).
    r      
   d   i'  @      P   i   )maxmin)r    r   S/var/www/html/Deteccion_Ine/venv/lib/python3.10/site-packages/modelscope/hub/api.py_calculate_adaptive_batch_sizev   s   r   c                   @   s6   e Zd ZdZdd ZdddZedd Zd	d
 ZdS )_CountedReadStreamzFile wrapper that counts bytes read and updates a progress bar.

    Unlike a generator, this is a file-like object that requests can
    use with Content-Length header for transfer integrity verification.
    c                 C   s"   || _ || _|| _|| _d| _d S Nr   )_file_expected_size_pbar_chunk_size_bytes_read)selfZfile_objZexpected_sizepbar
chunk_sizer   r   r   __init__   s
   
z_CountedReadStream.__init__c                 C   sP   |dk r| j nt|| j }| j|}|r&t|}|  j|7  _| j| |S )z-Read a chunk from the underlying file object.r   )r   r   r   readlenr   r   update)r   size	read_sizechunknr   r   r   r      s   z_CountedReadStream.readc                 C   s   | j S )zTotal bytes read so far.)r   r   r   r   r   
bytes_read   s   z_CountedReadStream.bytes_readc                 C   s*   | j | jkrtd| j  d| j ddS )z9Raise IOError if bytes read does not match expected size.zUpload data incomplete: read z bytes, expected z2 bytes. File may have been modified during upload.N)r   r   IOErrorr   r   r   r   verify_complete   s   
z"_CountedReadStream.verify_completeN)r   )	__name__
__module____qualname____doc__r   r   propertyr   r   r   r   r   r   r      s    


r   c                   @   sH  e Zd ZU dZdeedfdee dee fddZdefdd	Z	ddee dee
 fddZ		ddee dee fddZejejdddddfdedee dee dee dee dee dee ded defddZ			ddededee dee ded defddZddedee dee fddZddedee fd d!Zeddfded"ee dee dee def
d#d$Zddd%d&ed'ee dee defd(d)Zedd*d&ed"ee dee defd+d,Zddd*d&ed"ee dee defd-d.Zeedd/d&ed'ee d"ee dee deeef f
d0d1Z ddd
dd2d&ed'ee dee d3ee
 dee de
fd4d5Z!		dd&ed'edee dee fd6d7Z"e#d8d9 Z$ejejdd:de%ddddf
ded;edee dee dee d<ee d=ee d"ee dee d>eee&e ef  d?eeee&e f  dee fd@dAZ'	B	C		ddDedEee dFee dee dee defdGdHZ(dBdCdddddIdDedEee dFee dJee dKee dee dee defdLdMZ)ddNee
e*f de*fdOdPZ+		
ddedQee dNee
e*f de&e fdRdSZ,		
	ddedQee dNee
e*f dee de&e f
dTdUZ-dVdW Z.			ddedXee* dee fdYdZZ/			ddedXee* dee fd[d\Z0	
	ddedNee
e*f dee de1e&e e&e f fd]d^Z2	
ddedNee
e*f de1e&e e&e f fd_d`Z3edd
d
i dfded"ee daee dbee
 dNee
e*f dcee dee de&e fdddeZ4dddfd&edged"ee dee fdhdiZ5deje6jdddfdjedkedee dee dee dlee dee dee defdmdnZ7		ddoedee dee fdpdqZ8i Z9ee:dr< 		ddjedkedee dee fdsdtZ;	u	B	v		ddjedked"edwedbe
dEedFedee dee fdxdyZ<ee%dBdzddd{d&ed'ee d"ee dEedFedee dee fd|d}Z=e%d~dudBdvddddd&ed"edwedbe
dEedFedee dee dee fddZ>e%ddfdoed"ee dee dee fddZ?		ddjedkedoed"edee dee fddZ@e#dedefddZA		ddjedked"edededeBdee dee fddZCe#deDjEdfdee fddZFeGd
dudfdedjedked"ee dee
 dee
 dee fddZHeGdfdedjedked"ee dee f
ddZIeGddfdjedked"ee dee dee f
ddZJeGddfdjedkede
d"ee dee dee fddZKddoededee defddZL		ddjedked"ededee dee fddZM		ddee dee fddZN		ddedjedked"edee dee defddZO		ddedjedked"edee dee defddZPddee fddZQ		ddjedkede
dee dee ddfddZRdd ZS		
ddee de
deTeef fddZUe#dddeTeeVf fddZWdd&edee defddZXdeYjedejdd
dudd	d&edeee
df dee d'ee dee dee dee dee
 dee
 deeZ defddZ[ddee%ddd&ede\e] d<edee ded'ee d"ee dee de^fddÄZ_deddddd
e%dƜdeee`eaebf ded&edeedf d'ee d<ee dee dee dee dee
 d"ee de^fdd̈́Zcddτ Zdddф ZedddҜdeded&ed'ededefddքZfddee%dd؜d&ed<edee ded'ed"edede^fddۄZgdeBd'edeBfddބZhddddeddeieje%dߜ
d&edeee`e&e e&e` f dee d<ee dee deedf d'ee deee&e ef  deee&e ef  dede
d"ee deee^e&e^ f  fddZkdd Zld
dddddd&ed'edededeee`eaebf dee
 dee dee dee defddZmdddd&ed'ede&eTeeVf  dee dee deTeee f fddZn		ddeee`e&e e&e` f dedeee&e ef  deee&e ef  de&eeoeBf  f
ddZpe#de\e] d<edeTeeVf fddZqdderfddZsedddd&ed'edeee&e f d"ee dee dee deTeeVf fddZt	dd&ed'eud  deud deedf def
ddZv		B	z	dded'edEedFedee defddZw		dded	ee dee defd
dZxdS (  HubApizModel hub api interface.
    Nendpointtokenc              	   C   s   |dur|nt  | _|| _dt i| _t | _t|ddddt	dd}t
|d}| jd| | jd	| tD ]}t| j|tjt| j||d
 q8t | _dS )u   The ModelScope HubApi。

        Args:
            endpoint (str, optional): The modelscope server http|https address. Defaults to None.
        N
user-agent   )  i  i  i  T)totalr   connectbackoff_factorstatus_forcelistallowed_methodsrespect_retry_after_header)max_retrieszhttp://zhttps://timeout)r_   r   r   ModelScopeConfigget_user_agentheadersr   sessionr   r=   r   mountr*   setattr	functoolspartialgetattrUploadingCheckupload_checker)r   r   r   r   r   retryadaptermethodr   r   r   r      s2   

	
zHubApi.__init__access_tokenc                 C   sL   ddl m} ddlm} | jr|| jjnt }| }|jd||dd |S )z
        Get jar cookies for authentication from access_token.

        Args:
            access_token (str): user access token on ModelScope.

        Returns:
            jar (CookieJar): cookies for authentication.
        r   )RequestsCookieJar)urlparsem_session_id/)domainpath)Zrequests.cookiesr   urllib.parser   r   netlocr^   set)r   r   r   r   r   jarr   r   r   _get_cookies   s   
zHubApi._get_cookiesFcookies_requiredc                 C   sH   |p
| j p
tjd}|r| j|d}nt }|du r"|r"td|S )a  
        Get cookies for authentication from local cache or access_token.

        Args:
            access_token (Optional[str]): user access token on ModelScope. If not provided, try to get from local cache.
            cookies_required (bool): whether to raise error if no cookies found, defaults to `False`.

        Returns:
            cookies (CookieJar): cookies for authentication.

        Raises:
            ValueError: If no credentials found and cookies_required is True.
        MODELSCOPE_API_TOKENr   NzNo credentials found.You can pass the `--token` argument, or use HubApi().login(access_token=`your_sdk_token`). Your token is available at https://modelscope.cn/my/myaccesstoken)r   osenvirongetr   r   get_cookies
ValueError)r   r   r   r   cookiesr   r   r   r      s   zHubApi.get_cookiesc                 C   s   |p
| j p
tjd}|sdS |s| j}| d}| jj|d|i| | jd}t	| |
 }t| |t t }|j}t| t| t|t t |t t  |t t |fS )a|  Login with your SDK access token, which can be obtained from
           https://www.modelscope.cn user center.

        Args:
            access_token (str): user access token on modelscope, set this argument or set `MODELSCOPE_API_TOKEN`.
            If neither of the tokens exist, login will directly return.
            endpoint: the endpoint to use, default to None to use endpoint specified in the class

        Returns:
            cookies: to authenticate yourself to ModelScope open-api
            git_token: token to access your git repository.

        Note:
            You only have to login once within 30 days.
        r   NNz/api/v1/loginZAccessToken)jsonr   )r   r   r   r   r   r   postbuilder_headersr   rO   r   rP   r   r   r   r   
save_tokensave_cookiessave_user_infor   r   )r   r   r   r   rdr   r   r   r   r   login  s6   





zHubApi.login model_id
visibilitylicensechinese_nameoriginal_model_id
aigc_modelr\   r   c	                 C   sh  |du rt d| j|dd}	|s| j}t|\}
}|
|||||tjddd}|duri| d}|j|	| | j	|d	 |
|j|j|j|j|j|jpN||j|j|j|j|j|j|jd
 |jrh|j|d< n| d}| | j	}tdd }|dd| rd|d< | jj|||	|d}t| |  }t!| | d| }|dur|"| || |S )a  Create model repo at ModelScope Hub.

        Args:
            model_id (str): The model id in format {owner}/{name}
            visibility (int, optional): visibility of the model(1-private, 5-public), default 5.
            license (str, optional): license of the model, default apache-2.0.
            chinese_name (str, optional): chinese name of the model.
            original_model_id (str, optional): the base model id which this model is trained from
            endpoint: the endpoint to use, default to None to use endpoint specified in the class
            token (str, optional): access token for authentication
            aigc_model (AigcModel, optional): AigcModel instance for AIGC model creation.
                If provided, will create an AIGC model with automatic file upload.
                Refer to modelscope.hub.utils.aigc.AigcModel for details.

        Returns:
            str: URL of the created model repository

        Raises:
            InvalidParameter: If model_id is invalid or required AIGC parameters are missing.
            ValueError: If not login.

        Note:
            model_id = {owner}/{name}
        Nmodel_id is required!Tr   r   ZMODELSCOPE_TRAIN_IDr   )r   NameChineseNamerE   LicenseZOriginalModelIdZTrainIdz/api/v1/models/aigcr   r   r   )TagShowNameCoverImagesAigcTypeZTagDescriptionVisionFoundationZ	BaseModelWeightsNameWeightsSha256WeightsSizeZ	ModelPathTriggerWordsZModelSourceZSubVisionFoundationZOfficialTagsz/api/v1/models.r   r   en_USzX-Modelscope-Accept-Languager   r   r   /models/)#rG   r   r   rc   r   r   r   preupload_weightsr   r   r   tagcover_images	aigc_typedescriptionbase_model_typeZbase_model_idweight_filenameweight_sha256weight_sizeZ
model_pathtrigger_wordsZmodel_sourceZbase_model_sub_typeZofficial_tagsr!   splitrstripendswithr   r   rO   r   rP   Zupload_to_repo)r   r   r   r   r   r   r   r   r   r   owner_or_groupnamebodyr   r   Zintl_endr   r   Zmodel_repo_urlr   r   r   create_modelA  sj   !


zHubApi.create_modeltag_namec                 C   s  |du rt d|du rt d| dv rt d| d| j|dd}|s*| j}t|\}}|durZ| d	}	|j|| | j|d
 |j||||j	|j
|j|j|j|jd
}
n| d| d}	d}||d}
| jj|	|
|| | jd}t| | }t| | d| d| }|S )a]  Create a tag for a model at ModelScope Hub.

        Args:
            model_id (str): The model id in format {owner}/{name}
            tag_name (str): The tag name (e.g., "v1.0.0")
            endpoint: the endpoint to use, default to None to use endpoint specified in the class
            token (str, optional): access token for authentication
            aigc_model (AigcModel, optional): AigcModel instance for AIGC model tag creation.
                If provided, will create an AIGC model tag with automatic parameters.
                Refer to modelscope.hub.utils.aigc.AigcModel for details.

        Returns:
            str: URL of the created tag

        Raises:
            InvalidParameter: If model_id, tag_name, ref, or description is invalid.
            ValueError: If not login.

        Note:
            model_id = {owner}/{name}
        Nr   ztag_name is required!)mainmasterz
tag_name "zp" is not allowed. Please use a different tag name (e.g., "v1.0", "v1.1", "latest"). Reserved names: main, masterTr   z/api/v1/models/aigc/repo/tagr   )
r   r   r   r   r   r   r   r   r   r   /api/v1/models/z	/repo/tagr  )ZTagNameRefr   r   z/tags/)rG   lowerr   r   rc   r   r   r   r  r  r  r  r  r  r  r   r   rO   r   rP   )r   r   r  r   r   r   r   r  r  r   r  revisionr   r   Ztag_urlr   r   r   create_model_tag  sT   


zHubApi.create_model_tagc                 C   x   t jdtdd | j|dd}|s| j}|du rtd| d| }| jj||| | j	d	}t
| t|  dS )
a  
        @deprecated
        Delete model_id from ModelScope.

        Args:
            model_id (str): The model id.
            endpoint: the endpoint to use, default to None to use endpoint specified in the class
            token (str, optional): access token for authentication

        Raises:
            ValueError: If not login.

        Note:
            model_id = {owner}/{name}
        This function is deprecated due to security reasons, and will be recovered in future versions with proper token authentication. r   
stacklevelTr   N)Token does not exist, please login first.r  r   r   warningswarnDeprecationWarningr   r   r   r   deleter   r   rO   rP   r   )r   r   r   r   r   r   r   r   r   r   delete_model  s"   
zHubApi.delete_modelc                 C   s   |s| j }| d| dS )Nr  z.git)r   )r   r   r   r   r   r   get_model_url$  s   zHubApi.get_model_urlr  c           
      C   s   | j |dd}t|\}}|s| j}|r"| d| d| d| }n
| d| d| }| jj||| | jd}	t|	t|| |	j	t
jkrZt|	 rR|	 t S t|	 t t|	 dS )a  Get model information at ModelScope

        Args:
            model_id (str): The model id.
            revision (str optional): revision of model.
            endpoint: the endpoint to use, default to None to use endpoint specified in the class
            token (str, optional): access token for authentication

        Returns:
            The model detail information.

        Raises:
            NotExistError: If the model is not exist, will throw NotExistError

        Note:
            model_id = {owner}/{name}
        Fr   r  r   
?Revision=r  N)r   rc   r   r   r   r   r   rM   loggerstatus_coder   OKrN   r   r   rH   r   rO   )
r   r   r  r   r   r   r  r  r   r   r   r   r   	get_model)  s    

zHubApi.get_model)	repo_typer   repo_idr*  c          	      C   s  t jt}|dur6| dkr6t| }z| j|||d|d W |S  ty5   t	d| d| d  w t
t }t|d}| j||||d	st| d}td| d
| d| d z| j|||d|d W |S  ty   t	d| d| d|   w |S )a  Get proper endpoint for read operation (such as download, list etc.)
        1. If user has set MODELSCOPE_DOMAIN, construct endpoint with user-specified domain.
           If the repo does not exist on that endpoint, throw 404 error, otherwise return the endpoint.
        2. If domain is not set, check existence of repo in cn-site and ai-site (intl version) respectively.
           Checking order is determined by MODELSCOPE_PREFER_AI_SITE.
             a. if MODELSCOPE_PREFER_AI_SITE is not set ,check cn-site first before ai-site (intl version)
             b. otherwise check ai-site before cn-site
           return the endpoint with which the given repo_id exists.
           if neither exists, throw 404 error
        Nr   T)r+  r*  r   re_raiser   Repo z does not exist on r   )Zcn_siter*  r   r   z not exists on z#, will try on alternative endpoint r*  r   r,  r   z not exists on either z or )r   r   r   r%   stripr(   repo_exists	Exceptionr&  errorrb   r&   r_   warning)	r   r+  r*  r   sr   Zcheck_cn_firstZprefer_endpointZalternative_endpointr   r   r   get_endpoint_for_readV  s:   



zHubApi.get_endpoint_for_read)r  r   c          
      C   s^   t |\}}| j|||d}| j|t||d}| j||d|d}tdi ||||d}	|	S )aD  Get model information including commit history.

        Args:
            repo_id (str): The model id in the format of
                ``namespace/model_name``.
            revision (str, optional): Specific revision of the model.
                Defaults to ``DEFAULT_MODEL_REVISION``.
            endpoint (str, optional): Hub endpoint to use. When ``None``,
                use the endpoint specified when initializing :class:`HubApi`.

        Returns:
            ModelInfo: The model detailed information returned by
            ModelScope Hub with commit history.
        )r   r  r   r+  r*  r  r   T)r   r  	recursiver   commitsauthorsiblingsNr   )rc   r)  list_repo_commitsrj   get_model_filesrS   )
r   r+  r  r   r  _Z
model_datar:  r<  
model_infor   r   r   r@    s   zHubApi.model_infoc          
      C   sb   t |\}}| j|||d}| j|t||d}| j||ptd|d}tdi ||||d}	|	S )a>  Get dataset information including commit history.

        Args:
            repo_id (str): The dataset id in the format of
                ``namespace/dataset_name``.
            revision (str, optional): Specific revision of the dataset.
                Defaults to ``None``.
            endpoint (str, optional): Hub endpoint to use. When ``None``,
                use the endpoint specified when initializing :class:`HubApi`.

        Returns:
            DatasetInfo: The dataset detailed information returned by
            ModelScope Hub with commit history.
        )
dataset_idr  r   r7  T)r+  r  r8  r   r9  Nr   )rc   get_datasetr=  ri   get_dataset_filesrd   rR   )
r   r+  r  r   r  r?  Zdataset_datar:  r<  dataset_infor   r   r   rD    s   zHubApi.dataset_info)r*  r  r   c                C   sN   |du s|t kr| j|||dS |tkr| j|||dS td| dt d)aR  Get repository information for models or datasets.

        Args:
            repo_id (str): The repository id in the format of
                ``namespace/repo_name``.
            revision (str, optional): Specific revision of the repository.
                Currently only effective for model repositories. Defaults to
                ``DEFAULT_MODEL_REVISION``.
            repo_type (str, optional): Type of the repository. Supported
                values are ``"model"`` and ``"dataset"``. If not provided,
                ``"model"`` is assumed.
            endpoint (str, optional): Hub endpoint to use. When ``None``,
                use the endpoint specified when initializing :class:`HubApi`.

        Returns:
            Union[ModelInfo, DatasetInfo]: The repository detailed information
            returned by ModelScope Hub.
        N)r+  r  r   Arg repo_type z# not supported. Please choose from r   )rj   r@  ri   rD  rG   rk   )r   r+  r*  r  r   r   r   r   	repo_info  s   zHubApi.repo_infor/  r,  c                C   s  |du r| j }|dur| tvrtd| |du s"|ddkr(td| | j|dd}t|\}}|durJ| tkrJ| d| d| }	n
| d	| d| }	| jj	|	|| 
| jd
}
t|
t||d}|dkrodS |dkr{|ryt|
dS td| d td| )a  
        Checks if a repository exists on ModelScope

        Args:
            repo_id (`str`):
                A namespace (user or an organization) and a repo name separated
                by a `/`.
            repo_type (`str`, *optional*):
                `None` or `"model"` if getting repository info from a model. Default is `None`.
                TODO: support studio
            endpoint(`str`):
                None or specific endpoint to use, when None, use the default endpoint
                set in HubApi class (self.endpoint)
            re_raise(`bool`):
                raise exception when error
            token (`str`, *optional*): access token to use for checking existence.
        Returns:
            True if the repository exists, False otherwise.
        NzNot support repo-type: %sr   r   z5Invalid repo_id: %s, must be of format namespace/nameFr   /api/v1/datasets/r  r     Ti  z%Check repo_exists return status code r   zOFailed to check existence of repo: %s, make sure you have access authorization.)r   r  rk   r2  countr   rc   ri   r   r   r   r   rM   r&  r   r   )r   r+  r*  r   r,  r   r   r  r  r   r   coder   r   r   r1    s6   

zHubApi.repo_existsc                 C   st   t jdtdd |s| j}|tkr| j|||d n|tkr'| j|||d ntd| dt	
d| d	 d
S )al  
        @deprecated
        Delete a repository from ModelScope.

        Args:
            repo_id (`str`):
                A namespace (user or an organization) and a repo name separated
                by a `/`.
            repo_type (`str`):
                The type of the repository. Supported types are `model` and `dataset`.
            endpoint(`str`):
                The endpoint to use. If not provided, the default endpoint is `https://www.modelscope.cn`
                Could be set to `https://ai.modelscope.ai` for international version.
            token (str): Access token of the ModelScope.
        r  r   r  )rA  r   r   )r   r   r   rE  z not supported.r-  z deleted successfully.N)r  r   r!  r   ri   delete_datasetrj   r#  r2  r&  info)r   r+  r*  r   r   r   r   r   delete_repo  s*   zHubApi.delete_repoc                 C   s`   t j| tj}tjtjtj	t
ji}t|d}t|| W d    d S 1 s)w   Y  d S )Nw)r   r   joinrr   CONFIGURATIONrl   	frameworkrq   Ztorchtaskrs   otheropenr   dump)	model_dircfg_filecfgfiler   r   r   _create_default_configM  s   "zHubApi._create_default_configzupload modelrV  commit_messager   ignore_file_pattern
lfs_suffixc              
      s^  t jdtdd 	 |d u rtd|d u rtdtj|r%tj|r)tdtj|t	j
}tj|sItdt	j
 d| d	 t| | j|d
d}|d u rXtdt|}t|}|
d u rgg }
t|
tro|
g}
|d u sw|d u r{td| j||dstd| d | j|||||	|| jd tj|t}t }td| d| d td| d zzt|||| jd}||}||vrtd|  ||| ||| t|}|D ]$  d dkr
tj| }tj|rt| qt j!|d
d q|D ]9  d dkrEt" fdd|
D r$qtj| }tj#|r?t $|tj|  qt %|| q|sXt&j&' (d}d||f }|d urst|trf|gn|}|D ]}|)| qj|j*|||d |d ur|+|| td | d!| d" W n	 t,y    w W t j!|d
d d S t j!|d
d w )#NzThis function is deprecated and will be removed in future versions. Please use git command directly or use HubApi().upload_folder insteadr   r  zmodel_id cannot be empty!zmodel_dir cannot be empty!z$model_dir must be a valid directory.zNo z file found in z, creating a default one.Tr   zMust login before upload!z5Visibility and License cannot be empty for new model.r   zCreating new model [])r   r   r   r   r   r   r   zPushing folder z
 as model r   zTotal folder size z;, this may take a while depending on actual pushing size...)rV  Z
clone_from
auth_tokenr   zCreating new branch r   )ignore_errorsc                    s   g | ]
}t | d uqS N)research).0patternfr   r   
<listcomp>      z%HubApi.push_model.<locals>.<listcomp>z%Y_%m_%d_%H_%M_%Sz$[automsg] push model %s to hub at %s)r[  Zlocal_branchZremote_branchzSuccessfully push folder z to remote repo [z].)-r  r   r!  rG   r   r   existsisfilerO  rr   rP  r&  r4  r   rZ  r   rI   listdirr`   
isinstancestrr1  rL  r  r   r+   rQ   rU   Zget_remote_branchesZ
new_branchcheckoutremoveshutilrmtreeanyisdircopytreecopydatetimenowstrftimeZadd_lfs_typepushZtag_and_pushr2  )r   r   rV  r   r   r   r[  r   r  r   r\  r]  r   rW  r   Zfiles_to_saveZfolder_sizeZtmp_dirZgit_wrapperrepobranchesZfiles_in_reposrcdateZlfs_suffix_listsuffixr   rg  r   
push_modelW  s   /






"zHubApi.push_modelr   r   r  page_number	page_sizec           
      C   s   | j |dd}|s| j}| d}| jj|d|||f || | jd}t|t|| |jt	j
krGt| r?| t }	|	S t| t t| dS )aH  List models in owner or group.

        Args:
            owner_or_group(str): owner or group.
            page_number(int, optional): The page number, default: 1
            page_size(int, optional): The page size, default: 10
            endpoint: the endpoint to use, default to None to use endpoint specified in the class
            token (str, optional): access token for authentication

        Raises:
            RequestError: The request error.

        Returns:
            dict: {"models": "list of models", "TotalCount": total_number_of_models_in_owner_or_group}
        Fr   r  z.{"Path":"%s", "PageNumber":%s, "PageSize": %s})datar   r   N)r   r   r   putr   r   rM   r&  r'  r   r(  rN   r   r   rJ   r   rO   )
r   r  r  r  r   r   r   r   r   r  r   r   r   list_models  s(   

zHubApi.list_models)r  r  sortrd  r   r   r  rd  c                C   s   |s| j }| d}||d}	|r%|tvr!td| dtt ||	d< |r+||	d< |r1||	d< | j|dd	}
| jj||	|
d
}t| | |S )aq  List datasets via OpenAPI with pagination, filtering and sorting.

        Args:
            owner_or_group (str): Search by dataset authors (including organizations and individuals).
            page_number (int, optional): The page number. Defaults to 1.
            page_size (int, optional): The page size. Defaults to 10.
            sort (str, optional): Sort key. If not provided, the server's default sorting is used.
                choose from ['default', 'downloads', 'likes', 'last_modified'].
            search (str, optional): Search by substring keywords in the dataset's Chinese name,
                English name, and authors (including organizations and individuals).
            endpoint (str, optional): Hub endpoint to use. When None, use the endpoint specified in the class.
            token (str, optional): Access token for authentication.

        Returns:
            dict: The OpenAPI data payload, e.g.
                  {
                    "datasets": [...],
                    "total_count": int,
                    "page_number": int,
                    "page_size": int
                  }
        z/openapi/v1/datasets)r  r  zInvalid sort key: z. Supported sort keys: r  rd  r;  F)r   token_required)paramsr   )	r   rA   rG   list_build_bearer_headersr   r   rO   _parse_openapi_response)r   r  r  r  r  rd  r   r   r   r  r   r   r   r   r   list_datasets  s(   

zHubApi.list_datasetsuse_cookiesc                 C   s0   d }t |tr|}|S t |tr| j|d}|S )N)r   )rn  r   boolr   )r   r  r   r   r   r   _check_cookieL  s   

zHubApi._check_cookiecutoff_timestampc                 C   s.   | j |||d}|rdd |D }|S g }|S )a3  Get model branch and tags.

        Args:
            model_id (str): The model id
            cutoff_timestamp (int): Tags created before the cutoff will be included.
                                    The timestamp is represented by the seconds elapsed from the epoch time.
            use_cookies (Union[bool, CookieJar], optional): If is cookieJar, we will use this cookie, if True,
                        will load cookie from local. Defaults to False.

        Returns:
            Tuple[List[str], List[str]]: Return list of branch name and tags
        )r   r  r  c                 S      g | ]}|d  qS Revisionr   re  xr   r   r   ri  h      z/HubApi.list_model_revisions.<locals>.<listcomp>)list_model_revisions_detail)r   r   r  r  Ztags_detailstagsr   r   r   list_model_revisionsT  s   zHubApi.list_model_revisionsc           
      C   s   |  |}|du rt }|s| j}| d| d| }| jj||| | jd}t|t|| |	 }t
| |t }	|	d d S )a  Get model branch and tags.

        Args:
            model_id (str): The model id
            cutoff_timestamp (int): Tags created before the cutoff will be included.
                                    The timestamp is represented by the seconds elapsed from the epoch time.
            use_cookies (Union[bool, CookieJar], optional): If is cookieJar, we will use this cookie, if True,
                        will load cookie from local. Defaults to False.
            endpoint: the endpoint to use, default to None to use endpoint specified in the class

        Returns:
            Tuple[List[str], List[str]]: Return list of branch name and tags
        Nr  z/revisions?EndTime=%sr  RevisionMapTags)r  ra   r   r   r   r   r   rM   r&  r   rP   r   )
r   r   r  r  r   r   r   r   r   rL  r   r   r   r  l  s   


z"HubApi.list_model_revisions_detailc                 C   s"   |D ]}|d |kr|  S qd S )Nr  r   )r   detailsr  itemr   r   r   get_branch_tag_detail  s
   zHubApi.get_branch_tag_detailr   c                    sD  |s| j }t  tttj  }| j||d u rdn||d\}}|r,dd |D ng }|r7dd |D ng }	 |t krx|d u rNt	}t
d| d ||vr^||	vr^td||f | ||}
|
d u rn| ||}
t
d	|  |
S |d ur||v r| ||}
|
S t|d
kr|d u s|t	krt	}ntd||f | ||}
|
S |d u r|r fdd|D ng }t|d
kr|d
 d }|d
 }
nt	}| ||}
dd|	 }t
d|  t
d|  |
S ||	vr|t	krt
d | ||}
ndd|	 }td|||f | ||}
t
d|  |
S )NF)r  r   c                 S   r  r  r   r  r   r   r   ri    r  z4HubApi.get_valid_revision_detail.<locals>.<listcomp>c                 S   r  r  r   r  r   r   r   ri    r  z-Model revision not specified, using default [z
] version.z$The model: %s has no revision : %s .zDevelopment mode use revision: r   z#The model: %s has no revision: %s !c                    s   g | ]
}|d   kr|qS )Z	CreatedAtr   r  Zrelease_timestampr   r   ri    s    r  z[%s],z3Model revision should be specified from revisions: z,Model revision not specified, use revision: z?Using the master branch is fragile, please use it with caution!z0The model: %s has no revision: %s valid are: %s!z#Use user-specified model revision: )r   ra   introundrx  ry  	timestamp#get_model_branches_and_tags_detailsr)   rg   r&  rL  rH   r  debugr   rO  r4  )r   r   r  r   r   Zcurrent_timestampZall_branches_detailZall_tags_detailZall_branchesZall_tagsZrevision_detailZrevisions_detailZvlr   r  r   get_valid_revision_detail  st   

'



z HubApi.get_valid_revision_detailc                 C   s   | j ||||dd S )N)r   r  r   r   r  )r  )r   r   r  r   r   r   r   r   get_valid_revision  s   zHubApi.get_valid_revisionc           	      C   s|   |  |}|s
| j}| d| d}| jj||| | jd}t|t|| | }t	| |t
 }|d d |d d fS )a  Get model branch and tags.

        Args:
            model_id (str): The model id
            use_cookies (Union[bool, CookieJar], optional): If is cookieJar, we will use this cookie, if True,
                        will load cookie from local. Defaults to False.
            endpoint: the endpoint to use, default to None to use endpoint specified in the class

        Returns:
            Tuple[List[str], List[str]]: Return list of branch name and tags
        r  z
/revisionsr  r  ZBranchesr  )r  r   r   r   r   r   rM   r&  r   rP   r   )	r   r   r  r   r   r   r   r   rL  r   r   r   r    s   


z*HubApi.get_model_branches_and_tags_detailsc                 C   sF   | j ||d\}}|rdd |D ng }|rdd |D ng }||fS )aq  Get model branch and tags.

        Args:
            model_id (str): The model id
            use_cookies (Union[bool, CookieJar], optional): If is cookieJar, we will use this cookie, if True,
                        will load cookie from local. Defaults to False.

        Returns:
            Tuple[List[str], List[str]]: Return list of branch name and tags
        )r   r  c                 S   r  r  r   r  r   r   r   ri    r  z6HubApi.get_model_branches_and_tags.<locals>.<listcomp>c                 S   r  r  r   r  r   r   r   ri    r  )r  )r   r   r  Zbranches_detailZtags_detailr}  r  r   r   r   get_model_branches_and_tags  s   
z"HubApi.get_model_branches_and_tagsrootr8  r   c                 C   s  |s| j }|rd||||f }nd|||f }| |}	|dur'|d|  }|du r.| jn|}tt j|d< | jj||	|d}
t	|
t
|	| |
 }t| g }|t d sgt
d| d	| d
 |S |t d D ]}|d dks{|d dkr|qm|| qm|S )a  List the models files.

        Args:
            model_id (str): The model id
            revision (Optional[str], optional): The branch or tag name.
            root (Optional[str], optional): The root path. Defaults to None.
            recursive (Optional[bool], optional): Is recursive list files. Defaults to False.
            use_cookies (Union[bool, CookieJar], optional): If is cookieJar, we will use this cookie, if True,
                        will load cookie from local. Defaults to False.
            headers: request headers
            endpoint: the endpoint to use, default to None to use endpoint specified in the class

        Returns:
            List[dict]: Model file list.
        z7%s/api/v1/models/%s/repo/files?Revision=%s&Recursive=%sz+%s/api/v1/models/%s/repo/files?Recursive=%sNz&Root=zX-Request-IDr  FileszNo files found in model z at revision r   r   z
.gitignorez.gitattributes)r   r  r   ro  uuiduuid4hexr   r   rM   r&  r   rP   r   r4  append)r   r   r  r  r8  r  r   r   r   r   r   r   filesrY  r   r   r   r>    s:   
zHubApi.get_model_files)r  r   filenamec                C   s@   | j |d}| j|d||du rdn|d}dd |D }||v S )a  Get if the specified file exists

        Args:
            repo_id (`str`): The repo id to use
            filename (`str`): The queried filename, if the file exists in a sub folder,
                please pass <sub-folder-name>/<file-name>
            revision (`Optional[str]`): The repo revision
            token (`Optional[str]`): The access token
        Returns:
            The query result in bool value
        r   TNF)r8  r  r  c                 S   r  r   r   )re  rY  r   r   r   ri  f  r  z&HubApi.file_exists.<locals>.<listcomp>)r   r>  )r   r+  r  r  r   r   r  r   r   r   file_existsL  s   zHubApi.file_existsdataset_name	namespacer  c	                 C   s   |du s|du rt d| j|dd}	|s| j}| d}
d|fd|fd|fd|fd|fd|fd}| jj|
||	| | jd}t||
| t|	  | d| d	| }t
d
|  |S )aN  
        Create a dataset in ModelScope.

        Args:
            dataset_name (str): The name of the dataset.
            namespace (str): The namespace (user or organization) for the dataset.
            chinese_name (str, optional): The Chinese name of the dataset. Defaults to ''.
            license (str, optional): The license of the dataset. Defaults to Licenses.APACHE_V2.
            visibility (int, optional): The visibility of the dataset. Defaults to DatasetVisibility.PUBLIC.
            description (str, optional): The description of the dataset. Defaults to ''.
            endpoint (str, optional): The endpoint to use. If not provided, the default endpoint is used.
            token (str, optional): The access token for authentication.

        Returns:
            str: The URL of the created dataset repository.
        Nz(dataset_name and namespace are required!Tr   z/api/v1/datasets)r   r   ZOwnerr   rE   Description)r  r   r   z
/datasets/r   zCreate dataset success: )rG   r   r   r   r   r   r   rL   rP   r   r&  rL  )r   r  r  r   r   r   r  r   r   r   r   r  r   Zdataset_repo_urlr   r   r   create_dataseti  s0   
	
zHubApi.create_datasetrA  c                 C   r  )
ac  
        @deprecated
        Delete a dataset from ModelScope.

        Args:
            dataset_id (str): The dataset id to delete.
            endpoint (str, optional): The endpoint to use. If not provided, the default endpoint is used.
            token (str, optional): The access token for authentication.

        Returns:
            None
        r  r   r  Tr   Nr  rG  r  r  )r   rA  r   r   r   r   r   r   r   r   rK    s"   
zHubApi.delete_dataset_dataset_id_type_cachec                 C   s   |s| j }|||f}tj|}|dur|S | d| d| }| j|d}| jj||d}	|	 }
t||
|	 |
d d }|
d d }||ftj|< ||fS )	z Get the dataset id and type. NrG  r   r   r   DataZIdType)r   r   r  r   r   r   r   rK   )r   r  r  r   r   	cache_keycacheddatahub_urlr   r   resprA  dataset_typer   r   r   get_dataset_id_and_type  s   
zHubApi.get_dataset_id_and_typeTr   	root_pathc
                 C   s   t dt | j||||	d\}
}|rdnd}|s| j}| d|
 d}|r(|nd|r-|nd|||d	}| j|	d
}| jj|||d}| }t	||| |S )z?
        @deprecated: Use `get_dataset_files` instead.
        zMThe function `list_repo_tree` is deprecated, use `get_dataset_files` instead.r  r  r   r   TrueFalserG  
/repo/treer  r   r  ZRootZ	Recursive
PageNumberPageSizer   r  r   )
r  r   r!  r  r   r   r   r   r   rK   )r   r  r  r  r  r8  r  r  r   r   dataset_hub_idr  r  r  r   r   r  r   r   r   list_repo_tree  s&   

zHubApi.list_repo_tree2   )r*  r  r  r  r   r   c             
   C   s  t |r|ddkr|d\}}	ntd| d|s | j}|r-| d| d| dn| d| d}
|p8t||d	}| j|d
}z+| jj|
||| 	| j
d}t| | }t| |dtjkrlt|W S W dS  tjjy } ztd| dt| d}~ww )au  
        Get the commit history for a repository.

        Args:
            repo_id (str): The repository id, in the format of `namespace/repo_name`.
            repo_type (Optional[str]): The type of the repository. Supported types are `model` and `dataset`.
            revision (str): The branch or tag name. Defaults to `DEFAULT_REPOSITORY_REVISION`.
            page_number (int): The page number for pagination. Defaults to 1.
            page_size (int): The number of commits per page. Defaults to 50.
            endpoint (Optional[str]): The endpoint to use, defaults to None to use the endpoint specified in the class.
            token (Optional[str]): The access token.

        Returns:
            CommitHistoryResponse: The commit history response.

        Examples:
            >>> from modelscope.hub.api import HubApi
            >>> api = HubApi()
            >>> commit_history = api.list_repo_commits('meituan/Meeseeks')
            >>> print(f"Total commits: {commit_history.total_count}")
            >>> for commit in commit_history.commits:
            ...     print(f"{commit.short_id}: {commit.title}")
        r   r   Invalid repo_id:  !z/api/v1/s/z/commitsr  )r  r  r  r   r  r   r   Codez%Failed to get repository commits for : N)rw   rI  r	  r   r   rf   r   r   r   r   r   rO   r   rP   r   r(  r|   Zfrom_api_responserequests
exceptionsRequestExceptionr2  ro  )r   r+  r*  r  r  r  r   r   _owner_dataset_nameZcommits_urlr  r   r   r  er   r   r   r=    s6   !
zHubApi.list_repo_commitsr   )r  r  r8  r  r  r   r   r  r  c                C   s   |	du r*t |r|ddkr|d\}
}ntd| d| j||
||d\}	}|s/| j}| d|	 d}|||r=d	nd
||d}| j|d}| jj|||d}|	 }t
||| |d}|du rgg S |dpmg S )a  
        Get the dataset files.

        Args:
            repo_id (str): The repository id, in the format of `namespace/dataset_name`.
            revision (str): The branch or tag name. Defaults to `DEFAULT_REPOSITORY_REVISION`.
            root_path (str): The root path to list. Defaults to '/'.
            recursive (bool): Whether to list recursively. Defaults to True.
            page_number (int): The page number for pagination. Defaults to 1.
            page_size (int): The number of items per page. Defaults to 100.
            endpoint (Optional[str]): The endpoint to use, defaults to None to use the endpoint specified in the class.
            token (Optional[str]): The access token.
            dataset_hub_id (Optional[str]): Pre-fetched dataset hub id. When provided,
                skips the internal ``get_dataset_id_and_type`` lookup. Useful in pagination
                loops to avoid redundant API calls per page.

        Returns:
            List: The response containing the dataset repository tree information.
                e.g. [{'CommitId': None, 'CommitMessage': '...', 'Size': 0, 'Type': 'tree'}, ...]
        Nr   r   r  r  r  rG  r  r  r  r  r   r  r  r  )rw   rI  r	  r   r  r   r   r   r   r   rK   )r   r+  r  r  r8  r  r  r   r   r  r  r  r?  r  r  r   r   r  r  r   r   r   rC  =  s0    


zHubApi.get_dataset_filesc           	      C   s|   | j |d}|s| j}|r| d| d| }n| d| }| jj||| | jd}t| | }t||| |t	 S )a  
        Get the dataset information.

        Args:
            dataset_id (str): The dataset id.
            revision (Optional[str]): The revision of the dataset.
            endpoint (Optional[str]): The endpoint to use, defaults to None to use the endpoint specified in the class.
            token (Optional[str]): The access token.

        Returns:
            dict: The dataset information.
        r   rG  r%  r  )
r   r   r   r   r   r   rO   r   rK   r   )	r   rA  r  r   r   r   r   r   r  r   r   r   rB  {  s   zHubApi.get_datasetc                 C   s   |s| j }| d| d| }| j|d}| jj||| | jd}	|	 }
t||
|	 |
d }|du rBtd| d| d	| d
|d }|S )z( Get the meta file-list of the dataset. rG  z/repo/tree?Revision=r   r  r  Nz'The modelscope dataset [dataset_name = z, namespace = z, version = z] dose not existr  )	r   r   r   r   r   r   r   rK   rH   )r   r  r  rA  r  r   r   r  r   r   r  	file_listr   r   r   get_dataset_meta_file_list  s&   
z!HubApi.get_dataset_meta_file_listr  meta_cache_dirc                 C   sX   t j|t|  tjj }t|d}|d W d   dS 1 s%w   Y  dS )z
        Dump the data_type as a local file, in order to get the dataset
         formation without calling the datahub.
        More details, please refer to the class
        `modelscope.utils.constant.DatasetFormations`.
        rN  z3*** Automatically-generated file, do not modify ***N)	r   r   rO  ro  rm   Zformation_mark_extvaluerT  write)r  r  Zdataset_type_file_pathfpr   r   r   dump_datatype_file  s   "zHubApi.dump_datatype_filer  c	              
   C   s,  t t}	t|}
t|
 }| j|d}tj||d |s| j}|D ]q}|d }tj	
|d }||v r| d| d| d| d| 	}| jj||d	}t| tj	||}tj	|rotd
| d| d |	| | q t|d}||j W d    n1 sw   Y  |	| | q |	|
fS )Nr   )r  r  r   r   rG  r   /repo?Revision=
&FilePath=r  zReusing dataset z's python file ()wb)r   r  rm   rn   r   r   r  r   r   r   splitextr   r   rO   rO  rk  r&  r4  r  rT  r  content)r   r  r  r  r  r  r  r   r   Zlocal_pathsZdataset_formationZdataset_meta_formatr   	file_info	file_path	extensionr  r   Z
local_pathrh  r   r   r   "get_dataset_meta_files_local_paths  s>   z)HubApi.get_dataset_meta_files_local_paths   c                    s  ddl }ddlm} ddl}tj||| jdd	 }|t
jkr.tj|r.t| tj|r>td|  |S t j|d}td tj| |d	d
}	t|	jdd}
||
d	d} fdd}d}t|dQ}||	D ]D}|t| | drdd |D }t|dkrqs|dkrd	}nd}||}|j|d|dd |d7 }qs|D ]	}||d  qqsW d   n1 sw   Y  |  |S )zO
        Fetch the meta-data files from the url, e.g. csv/jsonl files.
        r   Nr   zUTF-8encodingzReusing cached meta-data file: r   zLoading meta-data file ...T)r   streamzcontent-length)r   Zdynamic_ncolsc                 3   sH    g }|   D ]}|d}|| t| kr|V  g }q|V  d S )Nutf-8)
iter_linesdecoder  r   )r  Z
chunk_datar  r   r   r   	get_chunk  s   


z3HubApi.fetch_meta_files_from_url.<locals>.get_chunkaZjsonlc                 S   s   g | ]}|  rt|qS r   )r0  r   loads)re  liner   r   r   ri    s    z4HubApi.fetch_meta_files_from_url.<locals>.<listcomp>F\)indexheader
escapecharr   
)hashlib	tqdm.autor   Zpandasr   r   rO  md5encode	hexdigestrp   ZFORCE_REDOWNLOADrk  rq  r&  rL  r   r   r  r   r  r   rT  r   r   r  Z	DataFrameZto_csvr  close)urlZout_pathr   moder   r  r   pdr   response
total_sizeprogressr  Ziter_numrh  r   Zwith_headerZchunk_dfr  r   r  r   fetch_meta_files_from_url  sH    





z HubApi.fetch_meta_files_from_url	file_nameviewextension_filterc           
      C   sR   |r|r|s
t dd|||d}t|}|s| j}| d| d| d| }	|	S )Nz:Args (file_name, dataset_name, namespace) cannot be empty!ZSDK)Sourcer  FilePathZViewrG  r   /repo?)r   r   r   )
r   r  r  r  r  r	  r
  r   r  file_urlr   r   r   get_dataset_file_url  s   
zHubApi.get_dataset_file_urlc              	   C   sF   |s| j }|r!tj|d tv r!| d| d| d| d| 	}|S )Nr   rG  r   r  r  )r   r   r   r  rh   )r   r  r  r  r  r   r   r   r   get_dataset_file_url_origin>  s   z"HubApi.get_dataset_file_url_originc                 C   s2   |s| j }| d| d| d| }| j||dS )NrG  r   /ststoken?Revision=r^  )r   datahub_remote_call)r   r  r  r  r   r   r  r   r   r   get_dataset_access_configL  s   z HubApi.get_dataset_access_configcheck_cookiec                 C   st   |s| j }| d| d| d| }|r| jdd}n| j|d}| jj||| | jd}	|	 }
t|
 |
d S )	NrG  r   r  T)r  r   r  r   r   r  )	r   r  r   r   r   r   r   r   rP   )r   r  r  r  r  r   r   r  r   r   r  r   r   r   !get_dataset_access_config_sessionY  s    	
z(HubApi.get_dataset_access_config_sessionversionc                 C   s   t jtjd}|stdtj | d}tj| j	|d}t
||d}t
|d}| jj|||| | jdd}	|	 }
|
d	 d
krLtd|
 |
d S )z.
        Get virgo dataset meta info.
        r   z"Virgo endpoint is not set in env: z/data/set/downloadr   )Z	dataSetIdZdataSetVersion)r  i  )r  r   r   r   r   rJ  r   zFailed to get virgo dataset: r  )r   r   r   rt   Zenv_virgo_endpointRuntimeErrorr  utilsdict_from_cookiejarr   dictr   r   r   r   r   )r   rA  r  r   Zvirgo_endpointZvirgo_dataset_urlr   rD  r  r   r  r   r   r   get_virgo_metas  s,   

zHubApi.get_virgo_metazip_file_namec                 C   s   |s| j }| d| d| }| j|d}| jj||| | jd}	|	 }
t|
 |
d }t|d }| d| }| jj||| | jd}| }t| |d }|d d | d	 | d	 | }||d
< |S )NrG  r   r   r  r  rE   r  z	-unzippedr?  ZDir)	r   r   r   r   r   r   r   rP   rF   )r   r  r  r  r  r   r   r  r   r   r  r  r   Zdatahub_sts_urlZr_stsZresp_stsZdata_stsZfile_dirr   r   r   &get_dataset_access_config_for_unzipped  s*   



 z-HubApi.get_dataset_access_config_for_unzippedc	                 C   sp   |s| j }| d| d| d| d| d| d| }	| j|d}
| jj|	|
dd	}| }t| |d
 }|S )NrG  r   z/oss/tree/?MaxLimit=
&Revision=z&Recursive=z&FilterDir=r   i  )r  r   r   r  )r   r   r   r   r   rP   )r   r  r  Z	max_limitZis_recursiveZis_filter_dirr  r   r   r  r   r  r   r   r   list_oss_dataset_objects  s"   zHubApi.list_oss_dataset_objectsobject_namec           
   	   C   |   |r|r|r|st d|s| j}| d| d| d| d| 	}| j|dd}| jj||d}	|	 }	t|	 |	d	 }	|	S )
NArgs cannot be empty!rG  r   z
/oss?Path=r  Tr   r  r   Messager   r   r   r   r"  r   rP   
r   r!  r  r  r  r   r   r  r   r  r   r   r   delete_oss_dataset_object  s    z HubApi.delete_oss_dataset_objectc           
   	   C   r"  )
Nr#  rG  r   z/oss/prefix?Prefix=z/&Revision=Tr   r$  r%  r&  r'  r   r   r   delete_oss_dataset_dir  s   zHubApi.delete_oss_dataset_dirc                 C   sB   | j |d}| jj||dt id}| }t||| |d S )Nr   r   r  r  )r   r   r   r   r   r   rK   )r   r  r   r   r   r  r   r   r   r    s   
zHubApi.datahub_remote_calluse_streamingc              
   C   s2  t ddk}|s| j}|r|r|s|szd| j|d}| d| d| d}| jj||| | jd}	t|	 t	j
j}
d}tt jv rGt jt }
tt jv rQt jt }| d| d| d	|
 d
| 	}| jj||| | jd}| }t| W d S  ty } zt| W Y d }~d S d }~ww d S d S d S d S )NZCI_TESTr  r   rG  r   z/download/increaser  r   z/download/uv/z?user=)r   getenvr   r   r   r   r   r   rO   ro   ZLOCALr  r"   r   r#   r   rP   r2  r&  r3  )r   r  r  r*  r   r   Z
is_ci_testr   Zdownload_count_urlZdownload_count_respZchannel	user_nameZdownload_uv_urlZdownload_uv_respr  r   r   r   dataset_download_statistics  s@   







z"HubApi.dataset_download_statisticsc                 C   s   t tt ji|S rb  )r'   ro  r  r  r  )r   r   r   r   r   r   	  s   zHubApi.builder_headersr  c                 C   sv   |  | j}|p| jptjd}|s(|  }|r(|D ]}|jdkr'|j} nq|r3d| |d< |S |r9t	d|S )a  
        Build HTTP headers with optional Bearer token for OpenAPI endpoints.

        Token resolution order:
            1. Explicit token param
            2. self.token (set at construction)
            3. MODELSCOPE_API_TOKEN env var
            4. Locally cached cookies (m_session_id from login())

        Args:
            token: Optional access token for one-time authentication.
            token_required: If True, raise ValueError when no token is available.

        Returns:
            Headers dict with user-agent, request-id, and optionally Authorization.

        Raises:
            ValueError: If token_required is True but no token is available.
        r   r   zBearer AuthorizationzAuthentication required but no token found. You can pass the `token` argument, or set MODELSCOPE_API_TOKEN environment variable, or use HubApi(token=`your_sdk_token`). Your token is available at https://modelscope.cn/my/myaccesstoken)
r   r   r   r   r   r   r   r  r  r   )r   r   r  r   Zresolved_tokenr   cookier   r   r   r    s(   
	zHubApi._build_bearer_headersr  zrequests.Responsec              
   C   s   z|   }W n  tjjtfy& } ztd|  td| |d}~ww t|t	rJd|v rJ|
ddu r?d|v r?|d S |
dpEd}t|t|t	rU|
di S i S )	a'  
        Parse OpenAPI response with unified JSON parsing and data extraction.

        Handles the standard OpenAPI response envelope:
            {"success": bool, "data": {...}, "message": str}
        Also handles the simpler envelope where only "data" is present.

        Args:
            response: requests Response object (HTTP status already validated).

        Returns:
            Parsed 'data' dict from the response envelope.

        Raises:
            RequestError: If JSON parsing fails or business-level error is returned.
        zJSON parsing failed: zInvalid JSON response: NsuccessTr  messagezOpenAPI request failed)r   r  r  JSONDecodeErrorr   r&  r3  rJ   rn  r  r   )r  r  r  msgr   r   r   r  >  s   zHubApi._parse_openapi_responsec                 C   s.   | d\}}|s| j}| d| d| dS )Nr   rG  r  )r	  r   )r   r+  r   Z
_namespacer  r   r   r   get_file_base_patha  s   zHubApi.get_file_base_path)	r   r   r*  r   r   r   exist_okcreate_default_configr   r5  r6  c       	      	   K   s  |st d|s| j}| j||||d}|r7|r/| d| d| }td| d|  |S t d| d|d}t|dkrFt d	|\}}|tkrd
d tj	
 D }|| }|du rkt d| d| j|||||
||d}|	rt 7}ddlm} |||||d}dddd}|d}|si }i ||}t|dt|gdd W d   n1 sw   Y  td| ddd |S |tkrdd tj	
 D }|| }|du rt d| d| j|||||||d}td| ddd |S t d | d!t )"a%  
        Create a repository on the ModelScope Hub.

        Args:
            repo_id (str): The repo id in the format of `owner_name/repo_name`.
            token (Union[str, bool, None]): The access token.
            visibility (Optional[str]): The visibility of the repo,
                could be `public`, `private`, `internal`, default to `public`.
            repo_type (Optional[str]): The repo type, default to `model`.
            chinese_name (Optional[str]): The Chinese name of the repo.
            license (Optional[str]): The license of the repo, default to `apache-2.0`.
            endpoint (Optional[str]): The endpoint to use.
                In the format of `https://www.modelscope.cn` or 'https://www.modelscope.ai'
            exist_ok (Optional[bool]): If the repo exists, whether to return the repo url directly.
            create_default_config (Optional[bool]): If True, create a default configuration file in the model repo.
            **kwargs: The additional arguments.

        Returns:
            str: The repo url.
        Repo id cannot be empty!r.  r   r  r-  z already exists, got repo url: z already exists!r   zBInvalid repo id, should be in the format of `owner_name/repo_name`c                 S       i | ]\}}| d s||qS __
startswithre  kvr   r   r   
<dictcomp>       z&HubApi.create_repo.<locals>.<dictcomp>NInvalid visibility: z9, supported visibilities: `public`, `private`, `internal`)r   r   r   r   r   r   r   r   rT   )r`  r   Zpytorchztext-generationT)rQ  rR  Zallow_remoteconfig_jsonzconfiguration.json)Zignore_push_errorz"New model created successfully at r   flushc                 S   r8  r9  r;  r=  r   r   r   r@    rA  )r  r  r   r   r   r   r   z$New dataset created successfully at Invalid repo type: , supported repos: )r   r   r1  r&  r4  r	  r   rj   rD   __dict__itemsr   upperr  tempfileTemporaryDirectorymodelscope.hub.repositoryrU   r]   r   dumpsprintri   rB   r  rk   )r   r+  r   r   r*  r   r   r   r5  r6  r   kwargsr1  repo_urlZrepo_id_listr  	repo_nameZvisibilitiesZtemp_cache_dirrU   r|  Zdefault_configrC  configr   r   r   create_repoh  s   $
	


	zHubApi.create_repo)commit_descriptionr   r*  r  r   
operationsrU  c                C   s.  |st d|s| j}|tvrt d| dt | d| d| d| }	|p,d| }|p0d}| j|d	d
}
| j||d}| jj|	| | jt	
||
d}|jdkryz|	 }W n t	jyh   |j}Y nw d|j d|	 d| }t ||	 }|di dd}td|	  t|	|||dS )a  
        Create a commit on the ModelScope Hub.

        Args:
            repo_id (str): The repo id in the format of `owner_name/repo_name`.
            operations (Iterable[CommitOperation]): The commit operations.
            commit_message (str): The commit message.
            commit_description (Optional[str]): The commit description.
            token (str): The access token. If None, will use the cookies from the local cache.
                See `https://modelscope.cn/my/myaccesstoken` to get your token.
            repo_type (Optional[str]): The repo type, should be `model` or `dataset`. Defaults to `model`.
            revision (Optional[str]): The branch or tag name. Defaults to `DEFAULT_REPOSITORY_REVISION`.
            endpoint (Optional[str]): The endpoint to use.
                In the format of `https://www.modelscope.cn` or 'https://www.modelscope.ai'
            timeout (int): Timeout for each request in seconds (default: 180).

        Returns:
            CommitInfo: The commit info.

        Raises:
            ValueError: If the request fails with a 4xx client error.
            requests.exceptions.RequestException: If a network-level error occurs.
        r7  rF  rG  /api/v1/repos/r  z/commit/z
Commit to r   Tr   )rV  r[  r   r  r   rH  zHTTP z error from r  r  oidzCommit succeeded: )Z
commit_urlr[  rU  rY  )r   r   rk   r   _prepare_commit_payloadr   r   r   r   r   rN  r'  r2  textr   r&  rL  r}   )r   r+  rV  r[  rU  r   r*  r  r   r  r   payloadr  Zerror_detail	error_msgr  rY  r   r   r   create_commit  sJ   #


zHubApi.create_commit   z[Uploading])r   r*  r[  rU  buffer_size_mb	tqdm_descdisable_tqdmr  path_or_fileobjpath_in_repor`  ra  rb  c             
   C   s  |t vrtd| dt  |std| j|dd t|ttfr5tjtj	|}|p3tj
|}n|s;tdt|tjrE| }| j| | jj|g|d |durZ|nd	| d
}|dkrhtdt||d}|d }|d }| j|||| jddd | j||||||
|	|d}t|||d}| j||rdnd|_|d |_|g}td| ddd | j|||||||d}|S )a  
        Upload a file to the ModelScope Hub.

        Args:
            path_or_fileobj (Union[str, Path, bytes, BinaryIO]):
                The local file path or file-like object (BinaryIO) or bytes to upload.
            path_in_repo (str): The path in the repo to upload to.
            repo_id (str): The repo id in the format of `owner_name/repo_name`.
            token (Union[str, None]): The access token. If None, will use the cookies from the local cache.
                See `https://modelscope.cn/my/myaccesstoken` to get your token.
            repo_type (Optional[str]): The repo type, default to `model`.
            commit_message (Optional[str]): The commit message.
            commit_description (Optional[str]): The commit description.
            buffer_size_mb (Optional[int]): The buffer size in MB for reading the file. Default to 1MB.
            tqdm_desc (Optional[str]): The description for the tqdm progress bar. Default to '[Uploading]'.
            disable_tqdm (Optional[bool]): Whether to disable the tqdm progress bar. Default to False.
            revision (Optional[str]): The branch or tag name. Defaults to `DEFAULT_REPOSITORY_REVISION`.

        Returns:
            CommitInfo: The commit info.

        Examples:
            >>> from modelscope.hub.api import HubApi
            >>> api = HubApi()
            >>> commit_info = api.upload_file(
            ...     path_or_fileobj='/path/to/your/file.txt',
            ...     path_in_repo='optional/path/in/repo/file.txt',
            ...     repo_id='your-namespace/your-repo-name',
            ...     commit_message='Upload file.txt to ModelScope hub'
            ... )
            >>> print(commit_info)
        rF  rG  z$Path or file object cannot be empty!Tr   z#Arg `path_in_repo` cannot be empty!file_path_listr*  NzUpload z to ModelScope hubr   z4Buffer size: `buffer_size_mb` must be greater than 0)file_path_or_objr`  	file_size	file_hashFr+  r   r*  r   r5  r6  )r+  r*  sha256r   r  rb  ra  r   rd  rc  file_hash_infolfsnormalis_uploadedzCommitting file to  ...rD  r+  rV  r[  rU  r   r*  r  )rk   r   r   rn  ro  r   r   r   abspathr   basenameioBufferedIOBaser   r   
check_filecheck_normal_filesru   rT  r   _upload_blobr   is_lfs_upload_mode_is_uploadedrO  r^  )r   rc  rd  r+  r   r*  r[  rU  r`  ra  rb  r  hash_info_drh  ri  
upload_resZadd_operationrV  commit_infor   r   r   upload_file(	  s~   /

zHubApi.upload_filec                 C   s0   |D ]}| |d |d |d  q|  dS )z1Mark files as uploaded and persist tracker state.file_path_in_repo
file_mtimefile_size_on_diskN)Zmark_uploadedsave)r   trackerresultsr   r   r   r   _track_uploaded_batch	  s   zHubApi._track_uploaded_batchc                 C   s    | dd |D  |  dS )z2Mark files as committed and persist tracker state.c                 S   s"   g | ]}|d  |d |d fqS )r  r  r  r   re  r   r   r   r   ri  	  s    z1HubApi._track_committed_batch.<locals>.<listcomp>N)Zmark_committed_batchr  )r   r  r  r   r   r   _track_committed_batch	  s   
zHubApi._track_committed_batch)r  pre_validatedr  r  c                C   s  |du rt  }d}d}	t|ttjf}
|
r;zt|}	|||	j|	j}|dur.|}||d< W n t	y:   d}	Y nw |du ret
|d}|
rez|	du rPt|}	|||	j|	j| W n	 t	yd   Y nw |	du r||
r|zt|}	W n	 t	y{   Y nw |d }|d }d}ttD ]}z8t|ttjfrtjt|}||krtd| d| d| | j||||||tkd	| d
 ||d	}W  nm ttjjtjjtfy# } zJt|tjjrt|dr|jdur|jjdk r |}|td k rtt| t}td|d  dt d| d| d| d t | W Y d}~qd}~ww t!dt d| d| ||||	r:|	jnd|	rA|	jn|"dd|d |"dd|dS )z5Hash and upload a single file, returning result dict.Nrg  )rg  rh  ri  z.File size changed since hash computation: was z, now z. File may have been modified: z[Uploading r_  )	r+  r*  rk  r   r  rb  ra  r   r  r  r   r   zBlob upload attempt r   z failed for r  , retrying in s ...zBlob upload failed after z attempts for r   rp  	is_reusedF)r  r  r  r  rp  r  rm  )#rY   rn  ro  r   PathLikestatget_hashst_mtimest_sizeOSErrorru   Zput_hashranger-   r   getsizer   ry  r1   ConnectionErrorr  r  r   hasattrr  r'  r   r.   r/   r&  r4  timesleepr  r   )r   r  r  r+  r*  r   r  r  r}  Z	file_statZis_real_pathr  rh  ri  
last_errorattemptZcurrent_sizer~  r  waitr   r   r   _upload_single_file	  s   







zHubApi._upload_single_file   )rU  r   r*  r  r   r   c                   s  d}	t |D ]}
z| j|||||||dW   S  ttjjfy/ } z|}	W Y d}~nsd}~w ttjjfy] } zt|drQ|jdurQd|jj  krPdk rQ  |}	W Y d}~nEd}~w t	y } z"t
| td r~ddg}t fd	d
|D s~ |}	W Y d}~nd}~w ty } z|}	W Y d}~nd}~ww td|
 d}td|
d  d| d|	 d| d	 t| qtd| d|	 |	)a  Commit with application-level exponential backoff retry.

        Retries on transient errors (5xx, ConnectionError) and specific
        retryable 4xx errors (e.g. git ref conflicts).
        Raises immediately on non-retryable client errors (4xx).
        Nrr  r  i  r   zHTTP 4\d{2}zCould not update refsz	try againc                 3       | ]}| v V  qd S rb  r   re  pZ	error_strr   r   	<genexpr>O
      z,HubApi._commit_with_retry.<locals>.<genexpr>r   <   zCommit attempt r   r   z	 failed: r  r  zCommit failed after z attempts: )r  r^  r  r  r  r   r  r  r'  r   ro  rc  rd  rt  r2  r   r&  r4  r  r  r  )r   r+  rV  r[  rU  r   r*  r  r   r  r  r  Zretryable_patternsr  r   r  r   _commit_with_retry"
  s`   	zHubApi._commit_with_retryr  c                 C   s\   g }|D ]'}t |d |d |d d}| j|d |rdnd|_|d |_|| q|S )z2Build CommitOperationAdd list from upload results.r  r  rm  rl  rn  ro  rp  )r   r   rz  r{  r|  r  )r   r  r*  rV  Zitem_doptr   r   r   _build_batch_operations_
  s   
zHubApi._build_batch_operations)
rd  r[  rU  r   r*  allow_patternsignore_patternsmax_workers	use_cacher  folder_pathr  r  r  r  c          D         s
  t   }s
td|du rtdtvr td dt jdd  r+ nd |	r1|	nd}	|	du r:g }	nt|	trB|	g}	|	t7 }	 durS fdd	|	D }	|durY|nd
 d}|pbd}ttg}|	du rn|}	nt|	try|	g| }	nt	|	| }	t
d j|| |	d}t|dkrtd| dt
dt| d jjdd	 |D d jjddd t|dd d}trtt|}t
d| dt| d n
tdkrtnt|}t|ttfrt| nt|d  j}|r|t }t|dnt tt||g }t t|D ]V\}\}}t|ttjfrkzt |}!||j"|j#rK$| %| W qW n t&yj } zt
'd| d |  W Y d}~nd}~ww |(|||ff qi }i }g }|D ]B\}\}}t|ttjfrzt |})||j"|j#}|dur||f||< W q~W n
 t&y   Y nw |(|||ff q~|rd!d	 |* D }j+|d"}|}t,d#d$ |* D }t
d%t| d&| d't||  d( t} | dkr	t
|  d) t
d*t| d+|  d,t| d- t
d.t| d/j- d0| d1 	dld2t.d3t/ffd4d5}!g }"g }#g }$j-}%zbt0|
d6M}&|D ](\}}'d}(||v rs|| d d7 })|1|)}(|(du rsd}(|&2|!||'|( qTt3t4|%d8|%d9D ]}*|*| }+t5|+| t|},t6fd:d$t4|+|,D rt
d;|*d<  d=|% d> q7|*\}-}.|.r|$8|. |.D ]\}/}0t
9d?|/d  d@|0  qƈ:|- ;|-}1|1st
9d;|*d<  d=|% dA q| dB|*d<  d=|% dC}2z2j<|1|2||dD}3|"(|3 |#8|- t
d;|*d<  d=|% dEt|- dF =|- W q t>y } zRt
9d;|*d<  d=|% dG|  |-D ]}4j?|4dH |4dI |4dJ dKdL qR|-D ]}4|$(|4dH |4dM f|f qgt
'd;|*d<  d=|% dNt|- dO W Y d}~qd}~ww W d   n	1 sw   Y  W @  n@  w |$rtArԈjB|$||||
dP	\}$}5}6|"8|5 |#8|6 n|$rt4tCD ]}7|$s nt
dQ|7d<  d=tC dRt|$ dS g }8g }9|$D ]A\\}}}:zjD||dT};|9(|; W q t>y< } zt
9dU| d@|  |8(||f|f W Y d}~qd}~ww |9r:|9 ;|9}1|1rz6j<|1| dV|7d<  dC||dD}3|"(|3 |#8|9 =|9 t
dW|7d<  dEt|9 dF W n5 t>y } z(t
9dW|7d<  dG|  |9D ]};|8(|;dH |;1dMdXf|f qW Y d}~nd}~ww |8}$qۈ@  t   | }<t|}=t|$}>t,dYd$ |#D }?t,dZd$ |#D }@tEd[ tEd\ tEd] tEd^|=  tEd_|   tEd`|?  tEda|@  tEdb|>  |?|@ }AtEdc|A  tEdd|<dedf tEd[ |$rW|$D ]\\}}B}0t
9dg| dNtF|0jG dN|0  q/|=|> }CtHdh|> di|C dj|"sj| t|krht
dk dS dS t|"d<kru|"d S |"S )mad  Upload a folder to ModelScope Hub with resumable support.

        Upload files from a local folder (or explicit file list) to a remote
        repository, with automatic batching, parallel upload, and progressive
        retry fallback (ReAct) for failed files.

        Args:
            repo_id: Repository identifier in 'owner/repo' format.
            folder_path: Local folder path, or a list of (path_in_repo, local_path) tuples.
            path_in_repo: Target directory path within the repository.
            commit_message: Commit message for the upload.
            commit_description: Optional extended commit description.
            revision: Branch or tag name (default: 'master').
            token: Authentication token. If None, uses stored credentials.
            repo_type: One of 'model', 'dataset', or 'space'.
            ignore_patterns: Glob patterns for files to exclude.
            max_workers: Max concurrent upload threads.
            use_cache: If True, uses .ms_upload_cache for resumable uploads.
                Files with matching path, mtime, and size that are already
                committed will be skipped automatically.

        Returns:
            None if all files were already committed (nothing to do).
            A single CommitInfo if only one batch was committed.
            A list of CommitInfo if multiple batches were committed.

        Raises:
            ValueError: If folder_path is empty or contains no valid files.
            RuntimeError: If any files remain failed after all retry rounds,
                with a message indicating the count and a retry hint.
        "The arg `repo_id` cannot be empty!Nz%The arg `folder_path` cannot be None!rF  rG  Tr   c                    s   g | ]}| vr|qS r   r   r  )r  r   r   ri  
  s    z(HubApi.upload_folder.<locals>.<listcomp>z
Upload to z on ModelScope hubzUploading fileszPreparing files to upload ...)folder_path_or_filesrd  r  r  r   z"No files to upload in the folder: r  z	Checking z files to upload ...c                 S   s   g | ]\}}|qS r   r   )re  r?  r  r   r   r   ri  
  r  re  Frj  c                 S   s   | d S r   r   )r  r   r   r   <lambda>
  s    z&HubApi.upload_folder.<locals>.<lambda>)keyzAdaptive batch size: z (for z files))r+  zCannot stat file z, will re-upload: c                 S   s"   g | ]\}}|d  |d dqS )ri  rh  rY  r   r   )re  rL  r?  r   r   r   ri  "  s    r+  r*  objectsr   c                 s   s    | ]	}|d u rdV  qd S )Nr   r   )re  r?  r   r   r   r  *  s    z'HubApi.upload_folder.<locals>.<genexpr>zPre-validated z cached hash(es): z globally existing, z need upload.z% file(s) already committed, skipping.zScan complete: z total, z committed (skip), z to process.z
Uploading z file(s) in z batch(es) of size z (pipeline mode).file_idxr  c              
      s   |\}}z&t d| d j|||d}t d|   | | W d S  tyO } zt d| d|   | || W Y d }~d S d }~ww )NzUploading: rq  )r+  r*  r   r  r  z
Uploaded: zUpload failed:  - )r&  r  r  Zrecord_successr2  r3  Zrecord_failure)r  r  r  rd  r  resultr  )batch_trackerr+  r*  r   r   r  r   r   _upload_worker>  s    z,HubApi.upload_folder.<locals>._upload_workerr  ri  z[Committing batches])descr   c                 3   r  rb  r   )re  i)skipped_indicesr   r   r  e  r  zBatch r   r   z fully committed, skipping.z
  Failed: r  z$: all files failed, skipping commit.z (batch r  rr  : committed 	 file(s). commit failed: r  r  r  Zcommit_failedZ
error_typer  r  z+ uploaded file(s) recovered to retry queue.)	failed_filesr  r+  r*  r   r[  rU  r  r  zRetry round z: re-uploading z failed file(s) ...r+  r*  r   r  z  Retry failed: z (retry round z  Retry round r   c                 s   s    | ]
}| d rdV  qdS r  r   Nr   r  r   r   r   r        

c                 s   s    | ]
}| d sdV  qdS r  r  r  r   r   r   r    r  z<============================================================zUpload Reportz<------------------------------------------------------------z  Total files      : z  Skipped (cached) : z  Existed (server) : z  Uploaded (PUT)   : z  Failed           : z  Committed        : z  Elapsed          : z.1fr5  z  - zERROR - zL file(s) failed to upload. Please manually try again. Successfully uploaded z8 file(s) will be automatically skipped during the retry.z!All files were already committed.rb  )Ir  r   rk   r   rn  ro  rz   rV   rX   r  r&  rL  _prepare_upload_folderr   r   rx  rT  r   sortedr,   r   r2   r   resolveparentrZ   rY   rW   r   	enumerater   r  r  Zis_committedr  r  addZmark_file_skippedr  r4  r  r  values_validate_blobsumnum_batchesr  tupler   r   submitr   r  r   allZwait_for_batchextendr3  r  r  r  r  r2  mark_failedr  r9   _retry_failed_files_reactr3   r  rO  typer   r  )Dr   r+  r  rd  r[  rU  r   r*  r  r  r  r  r  
start_timeZ_internal_ignoreprepared_repo_objectsZsorted_filesZcommit_batch_sizeZfolder_path_resolved
cache_pathZfiles_to_uploadr  r  str  Zpre_validated_mapZhash_info_mapZfiles_need_hashr  r  	validatedZreusedZskipped_countr  commit_infosZall_resultsZtotal_failed_filesr  executorr  pvcached_hashZ	batch_idxbatch_startZ	batch_endr  Zfailuresr  errrV  Zbatch_commit_messager  r   Zreact_commitsZreact_resultsZretry_roundZretry_failuresZretry_successes_errr  elapsedr   Zfailed_countZreused_countZuploaded_countZcommitted_countr?  Z	succeededr   )r  r  r+  r*  r   r  r   r  r   upload_folderr
  s  /











"




	

H
 


&
zHubApi.upload_folderc
           /      C   s  g }
g }i }g }t |}g }|D ][}|\\}}}t|}|jr%|| q|| zt|ttjfr8t|nd}W n t	yF   d}Y nw |j
||rO|jnd|rU|jnd|jd td| d|j d| d q|}dd	td
|	d dddddd
dtdddd
d
tdg}t|D ]\}}|s n|d }td| dt| d g }g }|d r-t|d
kr-ddlm}m} ||d dZ}i }|D ]\\}}} |j| j||||||d}!||f||!< q||D ]/}!||! \}}z|! }"||" W q ty }# z|||f|#f W Y d}#~#qd}#~#ww W d   n	1 s'w   Y  nt|D ]|\}$\\}}} |d dkro|$dkro|d
krU|d dt|$t  n|d }%t|%t}%td|% d| d t !|% z| j||||||d}"||" W q1 ty }# ztd| d| d |#  |||f|#f W Y d}#~#q1d}#~#ww |"| t|d! td
t|}&t#dt||&D ]{}'||'|'|&  }(| $||( | %|(|})|)sqz.| j&||)| d| d||||d"}*|
|* | '||( td| d#t|( d$ W q tyB }# z%td| d%|#  |(D ]}+||+d& |+d' f|#f q&W Y d}#~#qd}#~#ww g },|D ]}|\\}}}|(|dd
 ||< || d(kr|| zt|ttjfrtt|nd}W n t	y   d}Y nw |j
||r|jnd|r|jndd)d td*|  qGt|}|jr|,| qG|| zt|ttjfrt|nd}W n t	y   d}Y nw |j
||r|jnd|r|jnd|jd td| d|j d qGt|t|, }-|-dkrtd| d+|- d,t|, d- n|,r&t)d| d. |,}q|| }.|r;tdt| d/ |.|
|fS )0a  ReAct-style progressive retry for failed files.

        Implements Reason-Act-Observe loop with three escalating rounds:
          Round 1: Parallel retry with reduced concurrency (workers//2, batch=16)
          Round 2: Serial retry with exponential backoff (delay * 2^min(i, max_exp))
          Round 3: Single-file commit with long delays (one file per commit)

        Files that exceed the per-file retry limit are classified as permanent
        failures and will not be retried further.

        Args:
            failed_files: List of ((path_in_repo, file_path), error) tuples.
            tracker: UploadTracker or NullTracker instance.
            repo_id: Repository identifier.
            repo_type: Repository type.
            token: Authentication token.
            commit_message: Base commit message.
            commit_description: Commit description.
            revision: Branch or tag name.
            max_workers: Max upload concurrency from caller.

        Returns:
            Tuple of (all_failures, commit_infos, all_successes) where:
              - all_failures: list of ((path_in_repo, file_path), error) for
                files that could not be resolved (permanent + exhausted retries).
              - commit_infos: list of CommitInfo for successful retry commits.
              - all_successes: list of upload result dicts for successfully
                retried files (to be merged into the upload report).
        Nr   r  z[ReAct] Permanent failure: z (r  r  zRound 1 (parallel)Tr   r   r_  )r  parallelworkers
batch_sizedelayzRound 2 (serial+backoff)F   zRound 3 (single-file)r  z[ReAct] z: retrying z file(s) ...r  )r   as_completedr  r  r  r  z[ReAct] Waiting zs before retrying rq  z	: failed r  r  rr  r  r  r  r  r     Zmax_retries_exceededz![ReAct] Max retries exceeded for u   : made progress — z file(s) resolved, z remaining.z(: no progress, escalating to next round.z. file(s) still failing after all retry rounds.)*r  r[   Zis_retryabler  rn  ro  r   r  r  r  r  r  r  r  r&  r3  r   r;   r<   r  rL  r   concurrent.futuresr   r  r  r  r  r2  r   r8   r:   r  r  r  r  r  r  r  r  r   r4  )/r   r  r  r+  r*  r   r[  rU  r  r  r  Zall_successesretry_countsZpermanent_failuresZ	retryable	remainingZitem_errrd  r  r  categoryr  Zround_configsZ	round_idxrX  Z
round_nameZround_successesZround_failuresr   r  r  Z
future_mapr  futurer  r  r  r  r  r  batchrV  r  r   Znew_retryabler  Zall_failuresr   r   r   r    s  )








	








z HubApi._retry_failed_files_react)rb  ra  r`  r   r  rk  r   r  c       
      	   C   s|  t d ddd d d}|
du r$td|d d  d d|d< d|d< |S t|
tr,|
}n-| j||||d	g|	d
}||}|d u rYtd|d d  d d|d< d|d< |S | j|	dd}|rft |nd }|d u rptd| j	
dd|d  i | | j	}|d d }t||d< t|dd||dy}t|ttfrt|d}t||||}| jj|||td}W d    n1 sw   Y  |  n?t|trtt||||}| jj|||td}|  n!t|tjrt||||}| jj|||td}|  ntdW d    n	1 sw   Y  t|d | }t|d ||d< d|d< |d |d< |d |d< |S )NF)r  rp  r  r'  
status_msgTzBlob r  z  already exists globally, reuse.rp  r  r  r  r   r  Cookiezm_session_id=r   r  zContent-LengthB)r   unitZ
unit_scaler  disablerb)r   r  r   zInvalid data type to uploadZrspr  r  r'  r%  r  )r  r&  rL  rn  ro  r  r   r   r   r   r   r   r   r   rT  r   r   r  r0   r   bytesru  BytesIOrv  rO   r   rP   )r   r+  r*  rk  r   r  rb  ra  r`  r   r  Zres_dZ
upload_urlr  r   r   r   r   rh  r  r  r  r   r   r   ry    s   



	



,
zHubApi._upload_blob)r   r   r  c                C   s  |s| j }i }t}tdt||D ]{}||||  }	| d| d| d}
d|	d}| j|dd}| jj|
| | jt	
||d	}t|d
 |	 }t|d
 |d d }t }|D ]}|di }|d}|rz|d ||d < ||d  q\|	D ]}|d |vrd||d < q}q|S )a   Validate whether blobs need uploading.

        Queries the LFS batch API in chunks of UPLOAD_VALIDATE_BLOB_BATCH_SIZE.

        Args:
            repo_id: The repo id on ModelScope.
            repo_type: The repo type ('dataset', 'model', etc.).
            objects: Objects to check, each with 'oid' (sha256) and 'size'.
            endpoint: API endpoint override.
            token: Access token.

        Returns:
            Dict mapping oid -> upload_url (needs upload) or None (already exists).
        r   rW  r  z/info/lfs/objects/batchZupload)	operationr  Tr   rX  r  r  r  actionshrefrY  N)r   r@   r  r   r   r   r   r   r   r   rN  rO   rP   r   r   r  )r   r+  r*  r  r   r   r  r  r  r   r  r\  r   r  r  Zresp_objectsZneeds_uploadobjr  Zupload_actionor   r   r   r  r  sF   



zHubApi._validate_blobr  c           	         s6  d  d }t |trtj|d r|}ntdtj|r"|g}n| |d u rQ| j  t 	 
    sBtd  d fddt dD ni |D ]}tj|rk| j| |tj|< qUttj ||d}|r|d	 d	nd
fdd|D }tdt| d |S )Nr   z0Uploading multiple folders is not supported now.zProvided path: 'z' is not a directoryc                    s$   i | ]}|  r|  |qS r   )is_filerelative_toas_posix)re  r   )r  r   r   r@    s    z1HubApi._prepare_upload_folder.<locals>.<dictcomp>z**/*)r  r  r   r   c                    s    g | ]} | t | fqS r   )ro  )re  relpath)prefixrelpath_to_abspathr   r   ri    s    z1HubApi._prepare_upload_folder.<locals>.<listcomp>z	Prepared z files for upload.)rn  r  r   r   rl  r   r   check_folderr   r   r  is_dirr  globrw  rt  r   Zfilter_repo_objectskeysr0  r&  rL  r   )	r   r  rd  r  r  Z
files_pathr   Zfiltered_repo_objectsr  r   )r  r  r  r   r    sD   


zHubApi._prepare_upload_folderc              	   C   s  |g d}d}| D ]j}t |tr"|jr"td|j d |d7 }q	t |trE|jdkrEd|jd|jjd|	 
 d	d
}|d | q	t |trf|jdkrfd|jd|jj|jjddd
}|d | q	td| dt|dd |dkrtd| d |S )zN
        Prepare the commit payload to be sent to the ModelScope hub.
        )r[  r  r   zSkipping file 'z(' in commit (ignored by gitignore file).r   ro  creater   base64)actionr   r  r   rk  r  r  r  rn  z(Unknown operation to commit. Operation: z. Upload mode: r{  NzSkipped z/ file(s) in commit (ignored by gitignore file).)rn  r   Z_should_ignorer&  r  rd  r{  Zupload_infor   Z
b64contentr  r  rk  r   r   rL  )rV  r[  r\  Znb_ignored_filesr  Zcommit_actionr   r   r   rZ    sJ   

		
zHubApi._prepare_commit_payload皙?internal_timeoutc                 C   s~   dt dtfdd}| j d}|||d}d}|dur=| }d	|v r*|d	 d
 }nd}|r=|||d}|dur=|j }|S )a  
        Get the internal acceleration domain.

        Args:
            internal_timeout (float): The timeout for the request. Default to 0.2s

        Returns:
            str: The internal acceleration domain. e.g. `cn-hangzhou`, `cn-zhangjiakou`
        r  r   c                 S   s:   zt j| |d}|  W |S  t jjy   d }Y |S w )Nr   )r  r   raise_for_statusr  r  )r  r   r  r   r   r   send_request8  s   
z>HubApi._get_internal_acceleration_domain.<locals>.send_requestz&/api/v1/repos/internalAccelerationInfo)r  r   r   Nr  ZInternalRegionQueryAddressr   )ro  floatr   r   r[  r0  )r   r  r  Zinternal_urlZinternal_info_responseZ	region_idZ
query_addrZdomain_responser   r   r   !_get_internal_acceleration_domain-  s   	
z(HubApi._get_internal_acceleration_domain)r  r   r   delete_patternsc                 C   s  |t vrtd| |stdt|tr|g}| j|dd}|s%| j}|du r-td| | j}|tkrK| j	||p=t
d||d}	dd	 |	D }
nw|tkrg }
|d
\}}| j||||d\}}d}d}	 z| j||potd|||||d}W n ty } ztd| dt|  W Y d}~n#d}~ww |D ]}|d dkr|
|d  qt||k rn|d7 }qhn
td| dt  g }|
D ]}|D ]}t||r||  nqqg g }}|D ]}zb|tkr|d
\}}| d| d
| d}|pt
|d}n&|tkr |d
\}}| d| d
| d}d|i}n
td| dt  | jj||||d}t| | }t| || W q tyk } z|| td| dt|  W Y d}~qd}~ww ||t|dS )am  
        Delete files in batch using glob (wildcard) patterns, e.g. '*.py', 'data/*.csv', 'foo*', etc.

        Example:
            # Delete all Python and Markdown files in a model repo
            api.delete_files(
                repo_id='your_username/your_model',
                repo_type=REPO_TYPE_MODEL,
                delete_patterns=['*.py', '*.md']
            )

            # Delete all CSV files in the data/ directory of a dataset repo
            api.delete_files(
                repo_id='your_username/your_dataset',
                repo_type=REPO_TYPE_DATASET,
                delete_patterns='data/*.csv'
            )

        Args:
            repo_id (str): 'owner/repo_name' or 'owner/dataset_name', e.g. 'Koko/my_model'
            repo_type (str): REPO_TYPE_MODEL or REPO_TYPE_DATASET
            delete_patterns (str or List[str]): List of glob patterns, e.g. '*.py', 'data/*.csv', 'foo*'
            revision (str, optional): Branch or tag name
            endpoint (str, optional): API endpoint
            token (str, optional): Access token
        Returns:
            dict: Deletion result
        zUnsupported repo_type: zdelete_patterns cannot be emptyTr   Nr  )r  r8  r   r  c                 S   r  r   r   )re  rh  r   r   r   ri    r  z'HubApi.delete_files.<locals>.<listcomp>r   r  r   r   )r+  r  r8  r  r  r   r   r  zGet dataset: z file list failed, message: r  treer   rG  r  z/file)r  r  rG  z/repor  r  zFailed to delete r  )deleted_filesr  r   )rk   r   rn  ro  r   r   r   r   rj   r>  re   ri   r	  r  rC  rd   r2  r&  r3  r  r   fnmatchr   r"  rO   r   rP   ) r   r+  r*  r  r  r   r   r   r   r  
file_pathsr  r  Z_hub_idr?  r  r  Zdataset_filesr  Zfile_info_dZ	to_deleter   Zdelete_patternr  r  ownerrR  r  r  r  r   r  r   r   r   delete_filesT  s   $








&zHubApi.delete_files)modelZdatasetprivatepublicc                 C   s  |st d|dvrt d| ddd t D }||d}| j|dd	}|tkr| j||d
}| j d| }	|d}
d}t|
t	rY|
rY|
d }t|t
rY|rY|d}|dd|dd|d|dd|dd|dd|dd|dd|dd|di dd|di dd||ddd}nA|tkr|d }t|dkst|st d!| d"| j|d# |d |d$\}}| j d%| }	|dd&}n
t d'| d(t | jj|	||| | jd)}t| | }t| |S )*aK  
        Set the visibility of a repo.

        Args:
            repo_id (str): The repo id in the format of `owner_name/repo_name`.
            repo_type (Literal['model', 'dataset']): The repo type, `model` or `dataset`.
            visibility (Literal['private', 'public']): The visibility to set, `private` or `public`.
            token (Union[str, None]): The access token. If None, will use the cookies from the local cache.
                See `https://modelscope.cn/my/myaccesstoken` to get your token.

        Returns:
            dict: The response from the server.
        r  r  rB  z-, supported visibilities: `private`, `public`c                 S   s   i | ]\}}||qS r   r   r=  r   r   r   r@    s    z.HubApi.set_repo_visibility.<locals>.<dictcomp>r  Tr   )r   r   r  rs   r   r   r  r   ModelFrameworkZPytorchr   ApprovalModer  r   r   
ModelCoverSubScientificFieldNZNEXAScientificFieldr  r   )r   r  rE   ProtectedModer   r  r   r   r!  r"  r#  r  Z	ModelTaskr   r   zInvalid dataset repo_id: z-, should be in format of `owner/dataset_name`r   )r  r  r   rG  )rE   r$  rF  rG  r   )r   rF   rI  r   r   rj   r)  r   rn  r  r  ri   r	  r   r  r  rk   r   r  r   r   rO   r   rP   )r   r+  r*  r   r   Zvisibility_mapZvisibility_coder   r@  r   tasksZmodel_tasksfirstr\  Zrepo_id_partsZdataset_idxr?  r   r  r   r   r   set_repo_visibility  sn   













zHubApi.set_repo_visibilityskillcollection_idc                 C   s~   |s| j }|dkrtd| d|  }| d}||||d}| jj|||| | jd}	t|	 |	 }
t	|
 |
t
 S )a  Get collection details and its elements.

        Args:
            collection_id (str): The collection ID (Fid).
            repo_type (str): Element type filter, only 'skill' is supported currently.
            page_number (int): Page number for pagination.
            page_size (int): Page size for pagination.

        Returns:
            dict: Collection details including elements.

        Raises:
            ValueError: If repo_type is not 'skill'.
            RequestError: If the API request fails.
        r(  z
repo_type=z7 is not supported, only "skill" is currently supported.z/api/v1/collections)ZFidZElementTyper  r  r  )r   r   r   r   r   r   r   rO   r   rP   r   )r   r)  r*  r  r  r   r   r   r  r   r   r   r   r   get_collection4  s(   


zHubApi.get_collectionskill_id	local_dirc              	   C   s  |s| j }t|\}}|  }| d| d| d}|du r#t }tj|dd tj||}| j	j
|d|| | jd}	t|	 tj|| d}
zt|
d	}|	jd
dD ]	}|rc|| qZW d   n1 snw   Y  tj|r~t| tj|dd t|
d}|| W d   n1 sw   Y  t|}t|dkrtj||d }tj|rt|D ]}ttj||tj|| qt| W tj|
rt|
 ntj|
rt|
 w w td| d| d|  |S )a  Download a single skill archive and extract it.

        Args:
            skill_id (str): The skill identifier in format '<path>/<name>'.
            local_dir (Optional[str]): Target directory for extraction.
                Defaults to current directory.

        Returns:
            str: Path to the extracted skill directory.

        Raises:
            ValueError: If skill_id format is invalid.
            RequestError: If the download request fails.
        z/api/v1/skills/r   z/archive/zip/masterNTr5  )r  r   r   z.zipr  i    r  r   r   r   zSkill z downloaded to )r   r   Zvalidate_repo_idr   r   getcwdmakedirsr   rO  r   r   r   r   rO   rT  iter_contentr  rk  rr  rs  zipfileZipFile
extractallrm  r   ru  movermdirrq  r&  rL  )r   r+  r,  r   Zelement_pathZelement_namer   r  Z	skill_dirr   zip_pathrh  r   zfentriesZ
nested_dirr  r   r   r   download_skill^  s^   





zHubApi.download_skill)NFr   )NNNrb  )r   r   NN)F)NFN)FN)Tr   r   NN)r   N)FNN)r  )r(  r   r  N)yr   r   r   r   r   r   r   ro  r   r   r  r   r   rD   ZPUBLICrC   Z	APACHE_V2r  r  r  r#  r$  re   r  r)  r6  rS   r@  rR   rD  rj   r   rF  r1  rM  staticmethodrZ  rf   r   r  r  r  r   r  r  r  r  r  r  r   r  r  r>  r  rB   r  rK  r  __annotations__r  r  r=  rC  rB  r  r  r  r  rp   ZREUSE_DATASET_IF_EXISTSr  rd   r  r  r  r  r  r  r   r(  r)  r  r-  r   r   r  r	   r  r4  rE   r\   rT  r   r~   r}   r^  r   r  r
   r  r  r  r  r  r  r    r?   r  r  ry  r  r  r  rZ  r  r  r  r   r'  r*  r9  r   r   r   r   r      sH  
 
$ 
1
l
"W#
0
.
#
$

'
=
/
	

 
-
8



"
F


 



;
 
:
#
	
%
B	

A
$


$=
%


""




"

1"	

u	

W
	

 

n	

=

	

     	

u
F
9
?,

 
Y+r   c                   @   s   e Zd ZeeZdZdZdZdZ	dZ
edd Zedefdd	Zed
d Zedd ZedefddZededefddZedeeef fddZedee fddZeddeeedf defddZdS )r   r   Z	git_tokenuserr   Fc                   C   s   t jtjdd d S )NTr-  )r   r/  r   path_credentialr   r   r   r   make_sure_credential_path_exist  s   z0ModelScopeConfig.make_sure_credential_path_existc                 C   sR   t   ttjt jt jd}t	| | W d    d S 1 s"w   Y  d S )Nzwb+)
r   r>  rT  r   r   rO  r=  COOKIES_FILE_NAMEpicklerU  )r   rh  r   r   r   r     s   
"zModelScopeConfig.save_cookiesc                  C   s   t jtjtj} t j| rXt| d<}t	|}|s%	 W d    d S |D ]}|j
dkrF| rFtjsFdt_td  W d    d S q'|W  d    S 1 sSw   Y  d S )Nr  r   TzKNot logged-in, you can login for uploadingor accessing controlled entities.)r   r   rO  r   r=  r?  rk  rT  r@  loadr  
is_expiredcookie_expired_warningr&  rL  )Zcookies_pathrh  r   r/  r   r   r   r     s*   


 zModelScopeConfig.get_cookiesc                  C   s   t jtjtj} d}t j| r2t| d}t|	 
 dd}|W  d    S 1 s-w   Y  |dks<t|dkrbtt j}t  t| d}|| W d    |S 1 s]w   Y  |S )Nr   r  r  r      w+)r   r   rO  r   r=  USER_SESSION_ID_FILE_NAMErk  rT  ro  readliner0  r   r  r  r  r>  r  )Zsession_pathZ
session_idrh  Zwfr   r   r   get_user_session_id  s$   
 
z$ModelScopeConfig.get_user_session_idr   c                 C   sP   t   ttjt jt jd}||  W d    d S 1 s!w   Y  d S )NrE  )	r   r>  rT  r   r   rO  r=  GIT_TOKEN_FILE_NAMEr  r   rh  r   r   r   r     s   
"zModelScopeConfig.save_tokenr,  
user_emailc                 C   sX   t   ttjt jt jd}|d| |f  W d    d S 1 s%w   Y  d S )NrE  z%s:%s)	r   r>  rT  r   r   rO  r=  USER_INFO_FILE_NAMEr  )r,  rK  rh  r   r   r   r     s   
"zModelScopeConfig.save_user_infor   c                  C   s~   z4t tjtjtjddd} |  }|dd |dd fW  d    W S 1 s-w   Y  W dS  t	y>   Y dS w )Nr   r  r  :r   r   r   )
rT  r   r   rO  r   r=  rL  r   r	  FileNotFoundError)rh  rL  r   r   r   get_user_info  s"   
$	zModelScopeConfig.get_user_infoc                  C   sh   d} z't tjtjtjddd}| } W d   W | S 1 s"w   Y  W | S  ty3   Y | S w )z
        Get token or None if not existent.

        Returns:
            `str` or `None`: The token, `None` if it doesn't exist.

        Nr   r  r  )	rT  r   r   rO  r   r=  rI  r   rN  rJ  r   r   r   	get_token  s&   	

zModelScopeConfig.get_tokenN
user_agentc                 C   s   d}t tjv rtjt  }d}ttjv rtjt }ddlm} d|t t	 t t
 ||f }t| trH|dddd |  D  7 }|S t| trS|d|  7 }|S )	a  Formats a user-agent string with basic info about a request.

        Args:
            user_agent (`str`, `dict`, *optional*):
                The user agent info in the form of a dictionary or a single string.

        Returns:
            The formatted user-agent string.
        Zcustomunknownr   )__version__zSmodelscope/%s; python/%s; session_id/%s; platform/%s; processor/%s; env/%s; user/%sz; c                 s   s"    | ]\}}| d | V  qdS )r   Nr   r=  r   r   r   r  -  s     z2ModelScopeConfig.get_user_agent.<locals>.<genexpr>)r"   r   r   r#   Z
modelscoperS  platformpython_versionr   rH  	processorrn  r  rO  rI  ro  )rQ  envr,  rS  Zuar   r   r   r     s,   




	 
zModelScopeConfig.get_user_agentrb  )r   r   r   r   r$   r=  r?  rI  rL  rF  rC  r:  r>  r   r   r   rH  ro  r   r   r   rO  r   rP  r   r   r   r   r   r   r   r     s2    


$r   c                   @   s   e Zd ZdZeeeeefde	de	de	de	de	f
ddZ
dddZdeeef fddZdeeeeef ded	efddZdeeeef  ded	d
fddZd
S )r   a  
    Check the files and folders to be uploaded.

    Args:
        max_file_count (int): The maximum number of files to be uploaded. Default to `UPLOAD_MAX_FILE_COUNT`.
        max_file_count_in_dir (int): The maximum number of files in a directory.
            Default to `UPLOAD_MAX_FILE_COUNT_IN_DIR`.
        max_file_size (int): The maximum size of a single file in bytes. Default to `UPLOAD_MAX_FILE_SIZE`.
        size_threshold_to_enforce_lfs (int): The size threshold to enforce LFS in bytes.
            Files larger than this size will be enforced to be uploaded via LFS.
            Default to `UPLOAD_SIZE_THRESHOLD_TO_ENFORCE_LFS`.
        normal_file_size_total_limit (int): The total size limit of normal files in bytes.
            Default to `UPLOAD_NORMAL_FILE_SIZE_TOTAL_LIMIT`.

    Examples:
        >>> from modelscope.hub.api import UploadingCheck
        >>> upload_checker = UploadingCheck()
        >>> upload_checker.check_file('/path/to/your/file.txt')
        >>> upload_checker.check_folder('/path/to/your/folder')
        >>> is_lfs = upload_checker.is_lfs('/path/to/your/file.txt', repo_type='model')
        >>> print(f'Is LFS: {is_lfs}')
    max_file_countmax_file_count_in_dirmax_file_sizesize_threshold_to_enforce_lfsnormal_file_size_total_limitc                 C   s"   || _ || _|| _|| _|| _d S rb  )rX  rY  rZ  r[  r\  )r   rX  rY  rZ  r[  r\  r   r   r   r   J  s
   
zUploadingCheck.__init__r   Nc                 C   sl   t |ttfrtj|std| dt|}|| jkr4t	
d| jd  dt|d d d dS dS )	a  
        Check a single file to be uploaded.

        Args:
            file_path_or_obj (Union[str, Path, bytes, BinaryIO]): The file path or file-like object to be checked.

        Raises:
            ValueError: If the file does not exist or exceeds the size limit.
        File  does not existzFile exceeds size limit:    @z	 GB, got     GBN)rn  ro  r   r   r   rk  r   rv   rZ  r&  r4  r  )r   rg  rh  r   r   r   rw  X  s   

zUploadingCheck.check_filer  c                 C   s  d}d}t |trt|}| D ][}| r>|d7 }t|}|| jkr=td| d| jd  ddt	|d d d q|
 rl|d7 }| |\}}|| | jkrdtd	| d
||  d| j ||7 }||7 }q|| jkr}td| d| j ||fS )z
        Check a folder to be uploaded.

        Args:
            folder_path (Union[str, Path]): The folder path to be checked.

        Raises:
            ValueError: If the folder does not exist or exceeds the file count limit.
        r   r   r]  z exceeds size limit: r_  ra  zgot r`  z
Directory z
 contains z items and exceeds limit: zTotal file count z and exceeds limit: )rn  ro  r   iterdirr  rv   rZ  r&  r4  r  r  r  rY  r   rX  )r   r  Z
file_countZ	dir_countr  Z	item_sizeZsub_file_countZsub_dir_countr   r   r   r  k  s4   



zUploadingCheck.check_folderrg  r*  c                 C   s   d}t |ttfr;t|}| std| d|tkr%|jtvr$d}n|tkr1|jt	vr0d}n
td| dt
 t|}|| jkpE|S )aj  
        Check if a file should be uploaded via LFS.

        Args:
            file_path_or_obj (Union[str, Path, bytes, BinaryIO]): The file path or file-like object to be checked.
            repo_type (str): The repo type, either `model` or `dataset`.

        Returns:
            bool: True if the file should be uploaded via LFS, False otherwise.
        Tr]  r^  FrF  rG  )rn  ro  r   rk  r   rj   r  r{   ri   ry   rk   rv   r[  )r   rg  r*  Zhit_lfs_suffixrh  r   r   r   rz    s    

zUploadingCheck.is_lfsrf  c                    sT    fdd|D }t dd |D }|jkr(td|d  djd  ddS )	af  
        Check a list of normal files to be uploaded.

        Args:
            file_path_list (List[Union[str, Path]]): The list of file paths to be checked.
            repo_type (str): The repo type, either `model` or `dataset`.

        Raises:
            ValueError: If the total size of normal files exceeds the limit.

        Returns: None
        c                    s   g | ]
} | s|qS r   )rz  re  r  r*  r   r   r   ri    rj  z5UploadingCheck.check_normal_files.<locals>.<listcomp>c                 S   s   g | ]}t |qS r   )rv   rc  r   r   r   ri    r  zTotal size of non-lfs files i   zMB and exceeds limit: MBN)r  r\  r   )r   rf  r*  Znormal_file_listr  r   rd  r   rx    s   

z!UploadingCheck.check_normal_files)r   N)r   r   r   r   r4   r5   r6   r>   r7   r  r   rw  r   ro  r   r  r  r
   r  rz  r   rx  r   r   r   r   r   3  s,    

"&&r   )rx  r  r   ru  r   r@  rT  rc  rr  rK  r  r  r  r1  collectionsr   r  r   httpr   http.cookiejarr   Zos.pathr   pathlibr   typingr	   r
   r   r   r   r   r   r   r   r   r   r   r  r   Zrequests.adaptersr   r   Zrequests.exceptionsr   r  r   Zmodelscope.hub.constantsr   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   Zmodelscope.hub.errorsrG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   Zmodelscope.hub.gitrQ   Zmodelscope.hub.inforR   rS   rM  rU   Zmodelscope.hub.upload_cacherV   Zmodelscope.hub.upload_pipelinerW   Zmodelscope.hub.upload_trackerrX   rY   rZ   r[   Zmodelscope.hub.utils.aigcr\   Zmodelscope.hub.utils.utilsr]   r^   r_   r`   ra   rb   rc   Zmodelscope.utils.constantrd   re   rf   rg   rh   ri   rj   rk   rl   rm   rn   ro   rp   rq   rr   rs   rt   Zmodelscope.utils.file_utilsru   rv   rw   Zmodelscope.utils.loggerrx   Zmodelscope.utils.repo_utilsry   rz   r{   r|   r}   r~   r   r   r&  r  r   r   r   r   r   r   r   r   r   <module>   s   ,0*$L
(&                              
 