o
    tfN                  
   @   s  d Z ddlZddlZddlZddlZddlZddlZddlZddl	Z	ddl
ZddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ dd
lmZmZmZm Z m!Z!m"Z" ddl#m$Z$ ddl%m&Z& ddl'Z'ddl(Z(ddl)m*Z* ddl+m,Z,m-Z-m.Z.m/Z/m0Z0 ddl1m2Z2 ddl3m4Z4m5Z5m6Z6m7Z7 G dd dej8j9Z:dZ;e<dZ=e<dpe<dpe=Z>e<dpe<dpe>pe=Z?dZ@e>re$e>ZAeAjBCd\ZDZEZFe>e?dZ@e: Z;e;GeDeF de'jHdeIdeIdeIdeJf
dd ZKG d!d" d"e5ZLdS )#OExtension manager using pip as package manager and PyPi.org as packages source.    N)datetime	timedeltatimezone)partial)groupby)environ)Path)CalledProcessErrorrun)TarFile)AnyCallableDictListOptionalTuple)urlparse)ZipFile)
alru_cache)CFloatCIntUnicodeconfigobserve)__version__)ActionResultExtensionManagerExtensionManagerMetadataExtensionPackagec                   @   s   e Zd ZdddZdd ZdS )ProxiedTransportNc                 C   s   ||f| _ || _d S N)proxyproxy_headers)selfhostportheaders r(   c/var/www/html/software/conda/envs/catlas/lib/python3.10/site-packages/jupyterlab/extensions/pypi.py	set_proxy)   s   

zProxiedTransport.set_proxyc                 C   s,   t jj| j }|j|| jd ||f| _|S )Nr'   )httpclientHTTPConnectionr"   
set_tunnelr#   _connection)r$   r%   
connectionr(   r(   r)   make_connection-   s   
z ProxiedTransport.make_connection)NN)__name__
__module____qualname__r*   r2   r(   r(   r(   r)   r    (   s    
r    Z	ALL_PROXY
http_proxyZ
HTTP_PROXYZhttps_proxyZHTTPS_PROXY:)zhttp://zhttps://r-   namelatest_versionbase_urlreturnc                    s^   | j |d| d| d ddidI d H }|jdk r-t|j d  fdd	d
D S i S )N//jsonContent-Typeapplication/jsonr+     infoc                    s   i | ]}|  |qS r(   )get).0kdatar(   r)   
<dictcomp>Z   s    
z+_fetch_package_metadata.<locals>.<dictcomp>)	authorbugtrack_urldocs_url	home_pagelicensepackage_urlproject_urlproject_urlssummary)rB   status_codejsonloadstext)r-   r8   r9   r:   responser(   rE   r)   _fetch_package_metadataL   s   

rV   c                       sh  e Zd ZdZeddddZeddddZeddd	dZ	ed
dddZ
			d1dee dee deej ddf fddZedefddZdedee fddZdedefddZdededefddZedd d! Zd"ed#ed$edeeeef ee f fd%d&Z de!eeef  fd'd(Z"d2d)ed*ee de#fd+d,Z$dede#fd-d.Z%d)edefd/d0Z&  Z'S )3PyPIExtensionManagerr   zhttps://pypi.org/pypiTzThe base URL of PyPI index.)r   helpg     r@z.PyPI extensions list cache timeout in seconds.i  z$The cache size for package metadata.g      ?zGThrottling time in seconds between PyPI requests using the XML-RPC API.Napp_optionsext_optionsparentr;   c                    s   t  ||| tjtd| _tt| j| _| d| j	i t
jj| jtd| _tjtjdt| jd d | _d | _| jd| j d trT| jd	tj  d S d S )
N)proxiesnew)	transporttz)\(?secondsz%Extensions list will be fetched from .z=Extensions will be fetched using proxy, proxy host and port: )super__init__httpxAsyncClientr\   _httpx_clientr   rV   $_observe_package_metadata_cache_sizepackage_metadata_cache_sizexmlrpcr-   ServerProxyr:   xmlrpc_transport_override_rpc_clientr   nowr   utcr   cache_timeout5_PyPIExtensionManager__last_all_packages_request_time)_PyPIExtensionManager__all_packages_cachelogdebugrA   r"   )r$   rY   rZ   r[   	__class__r(   r)   rf      s"   

zPyPIExtensionManager.__init__c                 C   s   t ddtjS )zExtension manager metadata.PyPIT)r   sysprefixr$   r(   r(   r)   metadata   s   zPyPIExtensionManager.metadatapkgc                    s   z2| j j| jd| d ddidI dH }|jdk r&t|jdi }n| jd	| W dS W n
 t	y=   Y dS w t
|d
dpHdS )zReturn the latest available version for a given extension.

        Args:
            pkg: The extension to search for
        Returns:
            The latest available version
        r<   r=   r>   r?   r+   Nr@   rA   z+Failed to get package information on PyPI; version )ri   rB   r:   rQ   rR   rS   contentru   rv   	Exceptionr   get_semver_version)r$   r~   rU   rF   r(   r(   r)   get_latest_version   s   
z'PyPIExtensionManager.get_latest_version	extensionc                 C   s6   |j dur|j }|d dkr| |d S | |jS )a  Normalize extension name.

        Extension have multiple parts, npm package, Python package,...
        Sub-classes may override this method to ensure the name of
        an extension from the service provider and the local installed
        listing is matching.

        Args:
            extension: The extension metadata
        Returns:
            The normalized name
        NZpackageManagerpythonpackageName)install_normalize_namer8   )r$   r   Zinstall_metadatar(   r(   r)   get_normalized_name   s
   
z(PyPIExtensionManager.get_normalized_name	recursivefnc           	   
      s.  t jj }z|jd|g|R  I dH }W |S  tjjy } zq|jdkr}|j	
drd}td|j	}|durBt|dp@d}| jd| d	 t|| j d
 I dH  |ri| jd|g|R  I dH }n"|jd|g|R  I dH }W Y d}~|S W Y d}~|S W Y d}~|S W Y d}~|S d}~ww )a/  Throttle XMLRPC API request

        Args:
            recursive: Whether to call the throttling recursively once or not.
            fn: API method to call
            *args: API method arguments
        Returns:
            Result of the method
        Raises:
            xmlrpc.client.Fault
        NizHTTPTooManyRequests:ra   z!Limit may reset in (\d+) seconds.   1z>HTTPTooManyRequests - Perform next call to PyPI XMLRPC API in zs.g{Gz?F)tornadoioloopIOLoopcurrentrun_in_executorrl   r-   Fault	faultCodefaultString
startswithresearchintgroupru   rA   asynciosleeprpc_request_throttling&_PyPIExtensionManager__throttleRequest)	r$   r   r   argscurrent_looprF   errdelaymatchr(   r(   r)   Z__throttleRequest   s:   
$


z&PyPIExtensionManager.__throttleRequestrk   c                 C   s    t |d dtt| j| _d S )Nr]   )maxsize)r   r   rV   ri   )r$   Zchanger(   r(   r)   rj      s   

z9PyPIExtensionManager._observe_package_metadata_cache_sizequerypageper_pagec                    sj  |   I dH }i }d}|d | }|| }tt fdd|dd D ]\}	}
|d7 }||k s4||kr5q$t|
d \}}| |	|| jI dH }| |	}|dpSi }|d}|d	pb|d
}|dpl|d}|dpv|d}|p|dp|dp|p|p|}t||d||d|dt	
|d|||d|d||< q$|t|d | fS )aw  List the available extensions.

        Note:
            This will list the packages based on the classifier
                Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt

            Then it filters it with the query

            We do not try to check if they are compatible (version wise)

        Args:
            query: The search extension query
            page: The result page
            per_page: The number of results per page
        Returns:
            The available extensions in a mapping {name: metadata}
            The results last page; None if the manager does not support pagination
        Nr   c                    s    | d v S Nr   r(   )mr   r(   r)   <lambda>  s    z4PyPIExtensionManager.list_packages.<locals>.<lambda>c                 S   s   | d S r   r(   )er(   r(   r)   r         rO   zSource CoderK   ZHomepagerJ   ZDocumentationrI   zBug TrackerrN   rM   rP   rH   rL   Zprebuilt)r8   descriptionhomepage_urlrH   rL   r9   Zpkg_typebug_tracker_urldocumentation_urlZpackage_manager_urlZrepository_url))_PyPIExtensionManager__get_all_extensionsr   filterlistrV   r:   r   rB   r   r   r   mathceil)r$   r   r   r   matches
extensionscounter	min_indexZ	max_indexr8   r   _r9   rF   normalized_nameZpackage_urls
source_urlr   r   r   Zbest_guess_home_urlr(   r   r)   list_packages   sV   $

	z"PyPIExtensionManager.list_packagesc                    sj   | j d u stjtjd| jt| jd kr2| j	d | 
d| jjdgI d H | _ tjtjd| _| j S )Nr_   rb   z?Requesting PyPI.org RPC API for prebuilt JupyterLab extensions.Tz<Framework :: Jupyter :: JupyterLab :: Extensions :: Prebuilt)rt   r   rp   r   rq   rs   r   rr   ru   rv   r   ro   Zbrowser|   r(   r(   r)   Z__get_all_extensions6  s   z)PyPIExtensionManager.__get_all_extensionsr8   r   c                    s  t jj }t ?}tjd|dd$}|dt  |	  t
jddddd	d
dd|jg
}|dur@|  d|  n|  i }z?| }|dd |dd |dd |dtt|dddI dH }	t|	jd}
tt fdd|
dg }W n7 ty } z| jjd|j |d W Y d}~n+d}~w ty } z| jjd|d W Y d}~nd}~ww | jdt|
 d | jdd | d |dtt|dd I dH }	| jd!|	j!  | jd"|	jd  |	jd}|	j!d#kr| jd$|  d}z|d%i d&}|dur| j"|I dH }|j#d'k r|$d(rst%t&'|j()}td)d |) D ] t|* }|d*}|dur` nqJW d   n	1 smw   Y  nP|$d+rt+t&'|j(,}td,d |, D ] t-|.|/ }|d*}|dur nqW d   n	1 sw   Y  n| jd-| d.| W n ty } z| jjd/|d W Y d}~nd}~ww d0g}|dur|d1i }d2|v r|d2 d3|v r|d3 t0d4|d5W  d   W  d   S | j1d6  d7|	j! d8|  t0d9|d:W  d   W  d   S 1 s>w   Y  W d   dS 1 sOw   Y  dS );a  Install the required extension.

        Note:
            If the user must be notified with a message (like asking to restart the
            server), the result should be
            {"status": "warning", "message": "<explanation for the user>"}

        Args:
            name: The extension name
            version: The version to install; default None (i.e. the latest possible)
        Returns:
            The action result
        zw+F)modedirdeletezjupyterlab==-mpipr   
--no-inputz--quietz--progress-baroffz--constraintNz==r   z	--dry-runz--report-T)capture_outputcheckutf-8c                    s   |  di  d ddkS )Nr}   r8   r   r   )rB   replace)pr8   r(   r)   r   w  s    z.PyPIExtensionManager.install.<locals>.<lambda>z!Fail to get installation report: exc_infoz Fail to get installation report.zActions to be executed by pip rd   Executing ' 'r   return code: stdout: r   stderr: download_infourlr@   z.whlc                 S      t | jdkS Nzpackage.jsonr	   r8   fr(   r(   r)   r         
jupyterlabztar.gzc                 S   r   r   r   r   r(   r(   r)   r     r   zFailed to get 'z'; zFail to get package.json.frontend	discoverykernelserverokstatusZneeds_restartFailed to installed : code 
errorr   message)2r   r   r   r   tempfileTemporaryDirectoryNamedTemporaryFilewriter   flushrz   
executabler8   appendcopyinsertr   r   r   rR   rS   stdoutdecodenextr   rB   r
   ru   rv   stderrr   dumpsjoin
returncoderi   rQ   endswithr   ioBytesIOr   namelistreadr   getnamesloadextractfile	getmemberr   r   )r$   r8   r   r   Zve_dirZfconstraintcmdlineZ
pkg_actiontmp_cmdresultZaction_infor   r   r   jlab_metadataZdownload_urlrU   wheelrF   sdist
follow_upsr   r(   r   r)   r   D  s   



$



	








 f
VzPyPIExtensionManager.installc              
      s  t jj }tjddddd|g}d}zJ| }|d |dt	t
|ddI dH }td	d
 tdd
 |jd }tdd
 tt|D ]}t| }	|	d}|dur[ nqGW n tyw }
 z| jjd|
d W Y d}
~
nd}
~
ww | jdd| d |dt	t
|ddI dH }| jd|j  | jd|jd  |jd}|jdkr| jd|  dg}|dur|di }d|v r|d d|v r|d td|dS | jd| d|j d |  td!|d"S )#aj  Uninstall the required extension.

        Note:
            If the user must be notified with a message (like asking to restart the
            server), the result should be
            {"status": "warning", "message": "<explanation for the user>"}

        Args:
            extension: The extension name
        Returns:
            The action result
        r   r   	uninstallz--yesr   NTr   c                 S   s
   |  dS r   )r   liner(   r(   r)   r        
 z0PyPIExtensionManager.uninstall.<locals>.<lambda>c                 S   s   |   S r!   )stripr  r(   r(   r)   r     r   r   c                 S   s
   | j dkS r   r   r   r(   r(   r)   r     r  r   z%Fail to list files to be uninstalled.r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   r   rz   r   r   remover   r   r   r   mapr   r   
splitlinesr	   rR   rS   
read_bytesrB   r   ru   rv   r   r   r   r   r   r   )r$   r   r   r  r
  r  r	  linesfilepathrF   r   r   r  r   r(   r(   r)   r    sn   






 zPyPIExtensionManager.uninstallc                 C   s   | dd dd ddS )zNormalize extension name.

        Remove `@` from npm scope and replace `/` and `_` by `-`.

        Args:
            name: Extension name
        Returns:
            Normalized name
        @r   r<   r   r   )r   )r$   r8   r(   r(   r)   r     s   
z$PyPIExtensionManager._normalize_name)NNNr!   )(r3   r4   r5   __doc__r   r:   r   rr   r   rk   r   r   dictr   ZConfigurablerf   propertyr   r}   strr   r   r   boolr   r   r   r   rj   r   r   r   r   r   r   r   r   r  r   __classcell__r(   r(   rw   r)   rW   l   s\    "

FxIrW   )Mr  r   http.clientr,   r   rR   r   r   rz   r   xmlrpc.clientrl   r   r   r   	functoolsr   	itertoolsr   osr   pathlibr	   
subprocessr
   r   tarfiler   typingr   r   r   r   r   r   urllib.parser   zipfiler   rg   r   Z	async_lrur   Z	traitletsr   r   r   r   r   Zjupyterlab._versionr   Zjupyterlab.extensions.managerr   r   r   r   r-   	Transportr    rn   rB   Zall_proxy_urlZhttp_proxy_urlZhttps_proxy_urlr\   r6   netloc	partition
proxy_hostr   
proxy_portr*   rh   r  r  rV   rW   r(   r(   r(   r)   <module>   sj    

 