U
    qhE                  
   @  s  d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZmZmZmZmZ ddlmZ ddlmZ ddlZd	ejkre
ejd	 d
an4dejkre
ejd dd
ane
ejdddd
aG dd dZdddddZddddZdddddZdddddZd;dddd!d"d#Zdddd$d%d&Z d<dd(d)d*d+d,d-Z!d=ddd.dd/d0d1Z"d>ddd.ddd2d3d4d5Z#d?ddd.ddd(d3d6d7Z$d@ddddd.ddd2d8d9d:Z%dS )AzJONNX Model Hub

This implements the python client for the ONNX model hub.
    )annotationsN)BytesIO)join)IOAnyDictListcast)	HTTPError)urlopenZ	ONNX_HOMEZhubXDG_CACHE_HOMEonnx~z.cachec                   @  s<   e Zd ZdZdddddZddd	d
ZddddZdS )	ModelInfoaM  A class to represent a model's property and metadata in the ONNX Hub.
    It extracts model name, path, sha, tags, etc. from the passed in raw_model_info dict.

    Attributes:
        model: The name of the model.
        model_path: The path to the model, relative to the model zoo (https://github.com/onnx/models/) repo root.
        metadata: Additional metadata of the model, such as the size of the model, IO ports, etc.
        model_sha: The SHA256 digest of the model file.
        tags: A set of tags associated with the model.
        opset: The opset version of the model.
    zdict[str, Any]None)raw_model_inforeturnc                 C  s   t t|d | _t t|d | _t tttf |d | _d| _d| jkrZt t| jd | _t | _	d| jkrtt t
t | jd | _	t t|d | _|| _dS )zgInitializer.

        Args:
            raw_model_info: A JSON dict containing the model info.
        model
model_pathmetadataN	model_shatagsZopset_version)r	   strr   r   r   r   r   r   setr   r   intopsetr   )selfr    r   ,/tmp/pip-unpacked-wheel-xnis5xre/onnx/hub.py__init__+   s    

zModelInfo.__init__r   r   c              	   C  s&   d| j  d| j d| j d| j d	S )NzModelInfo(model=z, opset=z, path=z, metadata=))r   r   r   r   r   r   r   r   __str__@   s    zModelInfo.__str__c                 C  s   |   S N)r#   r"   r   r   r   __repr__C   s    zModelInfo.__repr__N)__name__
__module____qualname____doc__r   r#   r%   r   r   r   r   r      s   r   r   r   )new_dirr   c                 C  s   | a dS )zkSets the current ONNX hub cache location.

    Args:
        new_dir: Location of new model hub cache.
    N_ONNX_HUB_DIR)r*   r   r   r   set_dirG   s    r-   r    c                   C  s   t S )znGets the current ONNX hub cache location.

    Returns:
        The location of the ONNX hub model cache.
    r+   r   r   r   r   get_dirQ   s    r.   ztuple[str, str, str])repor   c                 C  sV   |  dd  dd }|  dd  dd }d| krH|  dd }nd}|||fS )zCGets the repo owner, name and ref from a repo specification string.:r   /   main)splitr/   
repo_owner	repo_namerepo_refr   r   r   _parse_repo_infoZ   s    r9   boolc                 C  s&   t | \}}}|dko$|dko$|dkS )zzVerifies whether the given model repo can be trusted.
    A model repo can be trusted if it matches onnx/models:main.
    r   modelsr3   r9   r5   r   r   r   _verify_repo_refe   s    r=   F)r/   lfsr   c                 C  sB   t | \}}}|r*d| d| d| dS d| d| d| dS )aT  Gets the base github url from a repo specification string.

    Args:
        repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main".
        lfs: Whether the url is for downloading lfs models.

    Returns:
        The base github url for downloading.
    z*https://media.githubusercontent.com/media/r1   z"https://raw.githubusercontent.com/r<   )r/   r>   r6   r7   r8   r   r   r   _get_base_urlm   s    r?   )url	file_namer   c              
   C  sN   d}t | 8}t|d"}||}|s*q6|| qW 5 Q R X W 5 Q R X dS )zDownloads the file with specified file_name from the url.

    Args:
        url: A url of download link.
        file_name: A specified file name for the downloaded file.
    i @  wbN)r   openreadwrite)r@   rA   
chunk_sizeresponsefchunkr   r   r   _download_file   s    
rJ   onnx/models:mainz
str | Nonezlist[str] | Nonezlist[ModelInfo])r/   r   r   r   c              
     s   t | }|d }z6t|$}dd tttt |D }W 5 Q R X W n2 tk
rx } ztd| |W 5 d}~X Y nX  dkr|n fdd|D }|dkr|S dd |D }	g }
|D ]0}d	d |j	D }t
|	|d
kr|
| q|
S )a  Gets the list of model info consistent with a given name and tags

    Args:
        repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        model: The name of the model to search for. If `None`, will
            return all models with matching tags.
        tags: A list of tags to filter models by. If `None`, will return
            all models with matching name.

    Returns:
        ``ModelInfo``s.
    zONNX_HUB_MANIFEST.jsonc                 S  s   g | ]}t |qS r   )r   ).0infor   r   r   
<listcomp>   s    zlist_models.<locals>.<listcomp>zCould not find manifest at Nc                   s"   g | ]}|j    kr|qS r   )r   lowerrL   mr   r   r   rN      s      c                 S  s   h | ]}|  qS r   rO   rL   tr   r   r   	<setcomp>   s     zlist_models.<locals>.<setcomp>c                 S  s   h | ]}|  qS r   rS   rT   r   r   r   rV      s     r   )r?   r   jsonloadr	   r   r   r
   AssertionErrorr   lenintersectionappend)r/   r   r   base_urlZmanifest_urlrG   manifestematching_modelsZcanonical_tagsZmatching_info_listrQ   Z
model_tagsr   rR   r   list_models   s,    
"ra   z
int | None)r   r/   r   r   c                   sz   t || }|std|   dkr6t|dd d}n< fdd|D }|srdd |D }t|  d	  d
| |d S )a  Gets the model info matching the given name and opset.

    Args:
        model: The name of the onnx model in the manifest. This field is
            case-sensitive
        repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        opset: The opset of the model to get. The default of `None` will
            return the model with largest opset.

    Returns:
        ``ModelInfo``.
    zNo models found with name Nc                 S  s   | j  S r$   r   )rQ   r   r   r   <lambda>       z get_model_info.<locals>.<lambda>)keyc                   s   g | ]}|j  kr|qS r   rb   rP   rb   r   r   rN      s     
 z"get_model_info.<locals>.<listcomp>c                 S  s   g | ]
}|j qS r   rb   rP   r   r   r   rN      s     z has no version with opset z. Valid opsets: r   )ra   rY   sorted)r   r/   r   r`   Zselected_modelsZvalid_opsetsr   rb   r   get_model_info   s    
rg   zonnx.ModelProto | None)r   r/   r   force_reloadsilentr   c              	   C  sr  t | ||}|jd}|jdk	r:|j d|d  |d< tttj|}|s\tj	|st
|s|sd| d}t|tjd td t  d	krdS tjtj|d
d t|d
}	td|  d|  t|	|j | ntd|  d|  t|d}
|
 }W 5 Q R X |jdk	rZt| }||jksZtd|j d| d|j dtttt t |S )a  Downloads a model by name from the onnx model hub.

    Args:
        model: The name of the onnx model in the manifest. This field is
            case-sensitive
        repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        opset: The opset of the model to download. The default of `None`
            automatically chooses the largest opset
        force_reload: Whether to force the model to re-download even if
            its already found in the cache
        silent: Whether to suppress the warning message if the repo is
            not trusted.

    Returns:
        ModelProto or None
    r1   N_The model repo specification _ is not trusted and may contain security vulnerabilities. Only continue if you trust this repo.fileContinue?[y/n]yTexist_okDownloading  to local path Using cached  model from rbThe cached model  has SHA256  while checksum should be h. The model in the hub may have been updated. Use force_reload to download the model from the model hub.)!rg   r   r4   r   r   r,   osseppathexistsr=   printsysstderrinputrO   makedirsdirnamer?   rJ   rC   rD   hashlibsha256	hexdigestrY   r   r   rX   r	   r   bytesr   )r   r/   r   rh   ri   selected_modelZlocal_model_path_arrZlocal_model_pathmsglfs_urlrH   Zmodel_bytesdownloaded_shar   r   r   rX      s6    

rX   c              	   C  s  t | ||}|jd d}|jd }|dk	rD| d|d  |d< tttj|}|sftj|st	|s|sd| d}	t
|	tjd	 t
d
 t  dkrdS tjtj|dd t|d}
t
d|  d|  t|
|jd  | nt
d|  d|  t|d}| }W 5 Q R X |dk	rbt| }||ksbtd|j d| d| d|dt|d  }tj|| |d t|d  }|S )aw  Downloads a model along with test data by name from the onnx model hub and returns the directory to which the files have been extracted.
    Users are responsible for making sure the model comes from a trusted source, and the data is safe to be extracted.

    Args:
        model: The name of the onnx model in the manifest. This field is
            case-sensitive
        repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        opset: The opset of the model to download. The default of `None`
            automatically chooses the largest opset
        force_reload: Whether to force the model to re-download even if
            its already found in the cache
        silent: Whether to suppress the warning message if the repo is
            not trusted.

    Returns:
        str or None
    model_with_data_pathr1   model_with_data_shaNrj   rk   rl   rm   rn   rp   rq   Trr   rt   ru   rv   rw   rx   ry   rz   r{   r|   r      )rg   r   r4   r   r,   r}   r~   r   r   r=   r   r   r   r   rO   r   r   r?   rJ   rC   rD   r   r   r   rY   r   rZ   r   utilsZ_extract_model_safelistdir)r   r/   r   rh   ri   r   Zlocal_model_with_data_path_arrr   Zlocal_model_with_data_pathr   r   rH   Zmodel_with_data_bytesr   Zlocal_model_with_data_dir_pathr   r   r   r   download_model_with_test_data$  sh    
 



	 
 r   )network_modelpreprocessing_modelnetwork_repopreprocessing_repor   rh   ri   r   c                 C  s  t |||||}|dkr&td| t | ||||}|dkrLtd|  t }	i }
i }|jD ],}|jdkrrdn|j}|	| |j|
|< q`|jD ],}|jdkrdn|j}|	| |j||< qd}d}|	D ]n}|dkr|| }|
| }q||kr||
kr|| || krtd| d|  d	| d
||  d|
|  dq||krltj	
||}|j|_tj| n,||krtj	
||}|j|_tj| dd t|jj|jjD }tjj|||d}|S )a  Builds a composite model including data preprocessing by downloading a network and a preprocessing model
    and combine it into a single model

    Args:
        network_model: The name of the onnx model in the manifest.
        preprocessing_model: The name of the preprocessing model.
        network_repo: The location of the model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        preprocessing_repo: The location of the proprocessing model repo in format
            "user/repo[:branch]". If no branch is found will default to
            "main"
        opset: The opset of the model to download. The default of `None`
            automatically chooses the largest opset
        force_reload: Whether to force the model to re-download even if
            its already found in the cache
        silent: Whether to suppress the warning message if the repo is
            not trusted.

    Returns:
        ModelProto or None
    Nz(Could not load the preprocessing model: z"Could not load the network model:  zai.onnxrk   zCan not merge z and z: because they contain different opset versions for domain z (z) and z\). Only the default domain can be automatically converted to the highest version of the two.c                 S  s   g | ]\}}|j |j fqS r   )name)rL   Z	out_entryZin_entryr   r   r   rN     s   z(load_composite_model.<locals>.<listcomp>)io_map)rX   RuntimeErrorr   Zopset_importdomainaddversion
ValueErrorr   Zversion_converterZconvert_versionZ
ir_versioncheckerZcheck_modelzipgraphoutputr   ZcomposeZmerge_models)r   r   r   r   r   rh   ri   ZpreprocessingnetworkZall_domainsZdomains_to_version_networkZ domains_to_version_preprocessingZopset_import_entryr   Zpreprocessing_opset_versionZnetwork_opset_versionr   Zmodel_with_preprocessingr   r   r   load_composite_model  s        




*
 
   r   )F)rK   NN)rK   N)rK   NFF)rK   NFF)rK   rK   NFF)&r)   
__future__r   r   rW   r}   r   ior   os.pathr   typingr   r   r   r   r	   urllib.errorr
   urllib.requestr   r   environr,   r   
expanduserr   r-   r.   r9   r=   r?   rJ   ra   rg   rX   r   r   r   r   r   r   <module>   s\   

)
	   2   #    C    ^     