
    -PhW                     t   d Z ddlZddlZddlZddlZddlmZ 	 ddlmZ n# e$ r dZY nw xY w	 ddl	Z	n# e$ r dZ	Y nw xY wdZ
ddZ G d	 d
          Z G d d          Z G d d          Z G d d          Zd Zd Z G d d          Z G d de          Z G d de          Z G d de          ZdS )z1
The classes that actually handle the downloads.
    N   	parse_url)tqdm   Fc           	         t           t          t          t          t          d}t	          |           }|d         |vr1t          d|d          d|  d|                                 d           ||d                  |          }|S )a  
    Choose the appropriate downloader for the given URL based on the protocol.

    Parameters
    ----------
    url : str
        A URL (including protocol).
    progressbar : bool or an arbitrary progress bar object
        If True, will print a progress bar of the download to standard error
        (stderr). Requires `tqdm <https://github.com/tqdm/tqdm>`__ to be
        installed. Alternatively, an arbitrary progress bar object can be
        passed. See :ref:`custom-progressbar` for details.

    Returns
    -------
    downloader
        A downloader class, like :class:`pooch.HTTPDownloader`,
        :class:`pooch.FTPDownloader`, or :class: `pooch.SFTPDownloader`.

    Examples
    --------

    >>> downloader = choose_downloader("http://something.com")
    >>> print(downloader.__class__.__name__)
    HTTPDownloader
    >>> downloader = choose_downloader("https://something.com")
    >>> print(downloader.__class__.__name__)
    HTTPDownloader
    >>> downloader = choose_downloader("ftp://something.com")
    >>> print(downloader.__class__.__name__)
    FTPDownloader
    >>> downloader = choose_downloader("doi:DOI/filename.csv")
    >>> print(downloader.__class__.__name__)
    DOIDownloader

    )ftphttpshttpsftpdoiprotocolzUnrecognized URL protocol 'z' in 'z'. Must be one of .)progressbar)FTPDownloaderHTTPDownloaderSFTPDownloaderDOIDownloaderr   
ValueErrorkeys)urlr   known_downloaders
parsed_url
downloaders        Q/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/pooch/downloaders.pychoose_downloaderr   #   s    L   3J*%666:*Z*@ : : : :/4466: : :
 
 	
 ;":j#9:{SSSJ    c                   $    e Zd ZdZddZ	 ddZdS )	r   a  
    Download manager for fetching files over HTTP/HTTPS.

    When called, downloads the given file URL into the specified local file.
    Uses the :mod:`requests` library to manage downloads.

    Use with :meth:`pooch.Pooch.fetch` or :func:`pooch.retrieve` to customize
    the download of files (for example, to use authentication or print a
    progress bar).

    Parameters
    ----------
    progressbar : bool or an arbitrary progress bar object
        If True, will print a progress bar of the download to standard error
        (stderr). Requires `tqdm <https://github.com/tqdm/tqdm>`__ to be
        installed. Alternatively, an arbitrary progress bar object can be
        passed. See :ref:`custom-progressbar` for details.
    chunk_size : int
        Files are streamed *chunk_size* bytes at a time instead of loading
        everything into memory at one. Usually doesn't need to be changed.
    **kwargs
        All keyword arguments given when creating an instance of this class
        will be passed to :func:`requests.get`.

    Examples
    --------

    Download one of the data files from the Pooch repository:

    >>> import os
    >>> from pooch import __version__, check_version
    >>> url = "https://github.com/fatiando/pooch/raw/{}/data/tiny-data.txt"
    >>> url = url.format(check_version(__version__, fallback="main"))
    >>> downloader = HTTPDownloader()
    >>> # Not using with Pooch.fetch so no need to pass an instance of Pooch
    >>> downloader(url=url, output_file="tiny-data.txt", pooch=None)
    >>> os.path.exists("tiny-data.txt")
    True
    >>> with open("tiny-data.txt") as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> os.remove("tiny-data.txt")

    Authentication can be handled by passing a user name and password to
    :func:`requests.get`. All arguments provided when creating an instance of
    the class are forwarded to :func:`requests.get`. We'll use
    ``auth=(username, password)`` to use basic HTTPS authentication. The
    https://httpbin.org website allows us to make a fake a login request using
    whatever username and password we provide to it:

    >>> user = "doggo"
    >>> password = "goodboy"
    >>> # httpbin will ask for the user and password we provide in the URL
    >>> url = f"https://httpbin.org/basic-auth/{user}/{password}"
    >>> # Trying without the login credentials causes an error
    >>> downloader = HTTPDownloader()
    >>> try:
    ...     downloader(url=url, output_file="tiny-data.txt", pooch=None)
    ... except Exception:
    ...     print("There was an error!")
    There was an error!
    >>> # Pass in the credentials to HTTPDownloader
    >>> downloader = HTTPDownloader(auth=(user, password))
    >>> downloader(url=url, output_file="tiny-data.txt", pooch=None)
    >>> with open("tiny-data.txt") as f:
    ...     for line in f:
    ...         print(line.rstrip())
    {
      "authenticated": true,
      "user": "doggo"
    }
    >>> os.remove("tiny-data.txt")

    F   c                 r    || _         || _        || _        | j        du rt          t	          d          d S d S NT2Missing package 'tqdm' required for progress bars.)kwargsr   
chunk_sizer   r   selfr   r$   r#   s       r   __init__zHTTPDownloader.__init__   sE    &$t##QRRR $#r   c                    ddl }|rR| j                            dt                    }|                    ||d          }t          |j        dk              }|S | j                                        }	|	                    dt                    }|		                    dd           t          |d           }
|
rt          |d	          }	  |j        |fd|i|	}|                                 |                    | j        
          }t          |j                            dd                    }| j        du r3t          t$          j        dk              }t)          |d|ddd          }n| j        r| j        }||_        |D ]N}|rJ|                    |           |                                 | j        r|                    | j                   O| j        r=|                                 |                    |           |                                 |
r|                                 n# |
r|                                 w w xY wdS )a  
        Download the given URL over HTTP to the given output file.

        Uses :func:`requests.get`.

        Parameters
        ----------
        url : str
            The URL to the file you want to download.
        output_file : str or file-like object
            Path (and file name) to which the file will be downloaded.
        pooch : :class:`~pooch.Pooch`
            The instance of :class:`~pooch.Pooch` that is calling this method.
        check_only : bool
            If True, will only check if a file exists on the server and
            **without downloading the file**. Will return ``True`` if the file
            exists and ``False`` otherwise.

        Returns
        -------
        availability : bool or None
            If ``check_only==True``, returns a boolean indicating if the file
            is available on the server. Otherwise, returns ``None``.

        r   NtimeoutT)r)   allow_redirects   streamwritew+b)r$   zcontent-lengthwin32O   Btotalncolsasciiunit
unit_scaleleave)requestsr#   getDEFAULT_TIMEOUTheadboolstatus_codecopypop
setdefaulthasattropenraise_for_statusiter_contentr$   intheadersr   sysplatformr   r3   r-   flushupdateresetclose)r&   r   output_filepooch
check_onlyr9   r)   response	availabler#   ispathcontentr3   	use_asciiprogresschunks                   r   __call__zHTTPDownloader.__call__   s}   : 	 	kooiAAG}}S'4}PPHX1S899I!!##**Y88(D)))['222 	3{E22K(	$#x|CCCCFCCH%%'''++t+GGG(,,-=qAABBE4'' !!899	##   ! '+!&  9 9 9%%e,,,%%'''' 9 !888
  !   &&&    $!!###  $!!####$ts   EH+ +INFr   F__name__
__module____qualname____doc__r'   rX    r   r   r   r   Z   sX        J JXS S S S 38V V V V V Vr   r   c                   0    e Zd ZdZ	 	 	 	 	 	 	 d
dZdd	ZdS )r   a  
    Download manager for fetching files over FTP.

    When called, downloads the given file URL into the specified local file.
    Uses the :mod:`ftplib` module to manage downloads.

    Use with :meth:`pooch.Pooch.fetch` or :func:`pooch.retrieve` to customize
    the download of files (for example, to use authentication or print a
    progress bar).

    Parameters
    ----------
    port : int
        Port used for the FTP connection.
    username : str
        User name used to login to the server. Only needed if the server
        requires authentication (i.e., no anonymous FTP).
    password : str
        Password used to login to the server. Only needed if the server
        requires authentication (i.e., no anonymous FTP). Use the empty string
        to indicate no password is required.
    account : str
        Some servers also require an "account" name for authentication.
    timeout : int
        Timeout in seconds for ftp socket operations, use None to mean no
        timeout.
    progressbar : bool
        If True, will print a progress bar of the download to standard error
        (stderr). Requires `tqdm <https://github.com/tqdm/tqdm>`__ to be
        installed. **Custom progress bars are not yet supported.**
    chunk_size : int
        Files are streamed *chunk_size* bytes at a time instead of loading
        everything into memory at one. Usually doesn't need to be changed.

       	anonymous NFr   c                     || _         || _        || _        || _        || _        || _        || _        | j        du rt          t          d          d S d S r!   )	portusernamepasswordaccountr)   r   r$   r   r   )r&   rf   rg   rh   ri   r)   r   r$   s           r   r'   zFTPDownloader.__init__,  sc     	  &$t##QRRR $#r   c                    t          |          }t          j        | j                  }|                    |d         | j                   |rt          j                            |d                   \  }}	 |	                    | j
        | j        | j                   ||                    |          v }	|                                 n# |                                 w xY w|	S t          d           }
|
rt!          d          	 |	                    | j
        | j        | j                   d|d          }| j        r|                    d	           t'          t(          j        d
k              }t-          t/          |                    |d                             d|ddd          5  fd}|                    ||| j                   ddd           n# 1 swxY w Y   n"|                    |j        | j                   |                                 |
r                                 n0# |                                 |
r                                 w w xY wdS )aZ  
        Download the given URL over FTP to the given output file.

        Parameters
        ----------
        url : str
            The URL to the file you want to download.
        output_file : str or file-like object
            Path (and file name) to which the file will be downloaded.
        pooch : :class:`~pooch.Pooch`
            The instance of :class:`~pooch.Pooch` that is calling this method.
        check_only : bool
            If True, will only check if a file exists on the server and
            **without downloading the file**. Will return ``True`` if the file
            exists and ``False`` otherwise.

        Returns
        -------
        availability : bool or None
            If ``check_only==True``, returns a boolean indicating if the file
            is available on the server. Otherwise, returns ``None``.

        r)   netloc)hostrf   path)userpasswdacctr-   r.   zRETR zTYPE Ir/   r0   r1   Tr2   c                 v                         t          |                                          |            dS z+Update the progress bar and write to outputN)rK   lenr-   )datarN   rV   s    r   callbackz(FTPDownloader.__call__.<locals>.callback|  s5     D		222#))$/////r   )	blocksizeN)r   ftplibFTPr)   connectrf   osrn   splitloginrg   rh   ri   nlstrM   rB   rC   r   voidcmdr=   rH   rI   r   rF   size
retrbinaryr$   r-   quit)r&   r   rN   rO   rP   r   r	   	directory	file_namerR   rS   commandrU   rv   rV   s     `           @r   rX   zFTPDownloader.__call__@  s   0 s^^
j...H-DI>>> 	#%7==F1C#D#D Iy		t}T]	VVV%))<)<<					['222 	3{E22K	$II4=T\IRRR2j022G V H%%% !899	chhz&'9::;;##    Q Q0 0 0 0 0 0
 NN7HNPPPQ Q Q Q Q Q Q Q Q Q Q Q Q Q Q w(9T_UUUHHJJJ $!!### HHJJJ $!!####$ts=   9>C C"B(H< 3$G#H< #G''H< *G'+&H< <-I))rb   rc   rd   rd   NFr   rZ   r[   r`   r   r   r   r     sh        " "L S S S S(H H H H H Hr   r   c                   ,    e Zd ZdZ	 	 	 	 	 	 d	dZd ZdS )
r   a  
    Download manager for fetching files over SFTP.

    When called, downloads the given file URL into the specified local file.
    Requires `paramiko <https://github.com/paramiko/paramiko>`__ to be
    installed.

    Use with :meth:`pooch.Pooch.fetch` or :func:`pooch.retrieve` to customize
    the download of files (for example, to use authentication or print a
    progress bar).

    Parameters
    ----------
    port : int
        Port used for the SFTP connection.
    username : str
        User name used to login to the server. Only needed if the server
        requires authentication (i.e., no anonymous SFTP).
    password : str
        Password used to login to the server. Only needed if the server
        requires authentication (i.e., no anonymous SFTP). Use the empty
        string to indicate no password is required.
    timeout : int
        Timeout in seconds for sftp socket operations, use None to mean no
        timeout.
    progressbar : bool or an arbitrary progress bar object
        If True, will print a progress bar of the download to standard
        error (stderr). Requires `tqdm <https://github.com/tqdm/tqdm>`__ to
        be installed.

       rc   rd   NFc                 $   || _         || _        || _        || _        || _        || _        g }| j        rt          |                    d           t          |                    d           |r"t          d
                    |                    d S )Nr"   z7Missing package 'paramiko' required for SFTP downloads. )rf   rg   rh   ri   r)   r   r   appendparamikor   join)r&   rf   rg   rh   ri   r)   r   errorss           r   r'   zSFTPDownloader.__init__  s     	  &  	PMMNOOOMMSTTT 	/SXXf--...	/ 	/r   c                 r  
 t          |          }t          j        |d         | j        f          }d}	 |                    | j        | j                   t          j                            |          }| j	        |
                                _        | j        r_t          |                    |d                   j                  }t!          t"          j        dk              }t'          |d|dd	d	
          
| j        r>
5  
fd}	|                    |d         ||	           ddd           n# 1 swxY w Y   n|                    |d         |           |                                 ||                                 dS dS # |                                 ||                                 w w xY w)aQ  
        Download the given URL over SFTP to the given output file.

        The output file must be given as a string (file name/path) and not an
        open file object! Otherwise, paramiko cannot save to that file.

        Parameters
        ----------
        url : str
            The URL to the file you want to download.
        output_file : str
            Path (and file name) to which the file will be downloaded. **Cannot
            be a file object**.
        pooch : :class:`~pooch.Pooch`
            The instance of :class:`~pooch.Pooch` that is calling this method.
        rl   )sockN)rg   rh   rn   r/   r0   r1   Tr2   c                     t          |          _                            t          | j        z
                       dS rs   )rF   r3   rK   n)currentr3   rV   s     r   rv   z)SFTPDownloader.__call__.<locals>.callback  s7    ),U Ghj,@(A(ABBBBBr   )rv   )r   r   	Transportrf   rz   rg   rh   
SFTPClientfrom_transportr)   get_channel
settimeoutr   rF   statst_sizer=   rH   rI   r   r:   rM   )r&   r   rN   rO   r   
connectionr   r   rU   rv   rV   s             @r   rX   zSFTPDownloader.__call__  s   " s^^
'j.BDI-NOOO
	NNN&55jAAD,0LD) 
499Z%788@AA !899	##    
: Q QC C C C C
 HHZ/xHPPPQ Q Q Q Q Q Q Q Q Q Q Q Q Q Q F+[999

   

  s0   CF	 $D3'F	 3D77F	 :D7; F	 	-F6)r   rc   rd   rd   NFr[   r`   r   r   r   r     sV         D / / / /41 1 1 1 1r   r   c                        e Zd ZdZddZd ZdS )r   a<  
    Download manager for fetching files from Digital Object Identifiers (DOIs).

    Open-access data repositories often issue Digital Object Identifiers (DOIs)
    for data which provide a stable link and citation point. The trick is
    finding out the download URL for a file given the DOI.

    When called, this downloader uses the repository's public API to find out
    the download URL from the DOI and file name. It then uses
    :class:`pooch.HTTPDownloader` to download the URL into the specified local
    file. Allowing "URL"s  to be specified with the DOI instead of the actual
    HTTP download link. Uses the :mod:`requests` library to manage downloads
    and interact with the APIs.

    The **format of the "URL"** is: ``doi:{DOI}/{file name}``.

    Notice that there are no ``//`` like in HTTP/FTP and you must specify a
    file name after the DOI (separated by a ``/``).

    Use with :meth:`pooch.Pooch.fetch` or :func:`pooch.retrieve` to be able to
    download files given the DOI instead of an HTTP link.

    Supported repositories:

    * `figshare <https://www.figshare.com>`__
    * `Zenodo <https://www.zenodo.org>`__
    * `Dataverse <https://dataverse.org/>`__ instances

    .. attention::

        DOIs from other repositories **will not work** since we need to access
        their particular APIs to find the download links. We welcome
        suggestions and contributions adding new repositories.

    Parameters
    ----------
    progressbar : bool or an arbitrary progress bar object
        If True, will print a progress bar of the download to standard error
        (stderr). Requires `tqdm <https://github.com/tqdm/tqdm>`__ to be
        installed. Alternatively, an arbitrary progress bar object can be
        passed. See :ref:`custom-progressbar` for details.
    chunk_size : int
        Files are streamed *chunk_size* bytes at a time instead of loading
        everything into memory at one. Usually doesn't need to be changed.
    **kwargs
        All keyword arguments given when creating an instance of this class
        will be passed to :func:`requests.get`.

    Examples
    --------

    Download one of the data files from the figshare archive of Pooch test
    data:

    >>> import os
    >>> downloader = DOIDownloader()
    >>> url = "doi:10.6084/m9.figshare.14763051.v1/tiny-data.txt"
    >>> # Not using with Pooch.fetch so no need to pass an instance of Pooch
    >>> downloader(url=url, output_file="tiny-data.txt", pooch=None)
    >>> os.path.exists("tiny-data.txt")
    True
    >>> with open("tiny-data.txt") as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> os.remove("tiny-data.txt")

    Same thing but for our Zenodo archive:

    >>> url = "doi:10.5281/zenodo.4924875/tiny-data.txt"
    >>> downloader(url=url, output_file="tiny-data.txt", pooch=None)
    >>> os.path.exists("tiny-data.txt")
    True
    >>> with open("tiny-data.txt") as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> os.remove("tiny-data.txt")

    Fr   c                 0    || _         || _        || _        d S N)r#   r   r$   r%   s       r   r'   zDOIDownloader.__init__L  s    &$r   c                 
   t          |          }t          |d                   }|d         }|d         dk    r
|dd         }|                    |          }t          d| j        | j        d| j        } ||||           dS )	a7  
        Download the given DOI URL over HTTP to the given output file.

        Uses the repository's API to determine the actual HTTP download URL
        from the given DOI.

        Uses :func:`requests.get`.

        Parameters
        ----------
        url : str
            The URL to the file you want to download.
        output_file : str or file-like object
            Path (and file name) to which the file will be downloaded.
        pooch : :class:`~pooch.Pooch`
            The instance of :class:`~pooch.Pooch` that is calling this method.

        rl   rn   r   /r   N)r   r$   r`   )r   doi_to_repositorydownload_urlr   r   r$   r#   )	r&   r   rN   rO   r   data_repositoryr   r   r   s	            r   rX   zDOIDownloader.__call__Q  s    ( s^^
+Jx,@AA v&	Q<3!!""I&33I>> $ 
(T_
 
HL
 

 	
<e44444r   NrY   r[   r`   r   r   r   r     sD        O Ob% % % %
"5 "5 "5 "5 "5r   r   c                     ddl }|                    d|  t                    }|j        }d|j        cxk    rdk     rn nt          d|  d| d	          |S )
z
    Follow a DOI link to resolve the URL of the archive.

    Parameters
    ----------
    doi : str
        The DOI of the archive.

    Returns
    -------
    url : str
        The URL of the archive in the data repository.

    r   Nzhttps://doi.org/rk     X  zArchive with doi:z not found (see z). Is the DOI correct?)r9   r:   r;   r   r>   r   )r   r9   rQ   r   s       r   
doi_to_urlr   v  s      OOO ||4s44o|NNH
,C
h"((((S(((((PPPSPPP
 
 	
 Jr   c                    | d         dk    r
| dd         } t           t          t          g}t          |           }d}|D ]}||                    ||           }|(t          |          d         }t          d| d          |S )a]  
    Instantiate a data repository instance from a given DOI.

    This function implements the chain of responsibility dispatch
    to the correct data repository class.

    Parameters
    ----------
    doi : str
        The DOI of the archive.

    Returns
    -------
    data_repository : DataRepository
        The data repository object
    r   N)archive_urlr   rl   zInvalid data repository 'zy'. To request or contribute support for this repository, please open an issue at https://github.com/fatiando/pooch/issues)FigshareRepositoryZenodoRepositoryDataverseRepositoryr   
initializer   r   )r   repositoriesr   r   repo
repositorys         r   r   r     s    * 2w#~~#2#h 	L S//K O  ""oo' .  O
 {++H5
O
 O O O
 
 	
 r   c                   0    e Zd Zed             Zd Zd ZdS )DataRepositoryc                     dS )  
        Initialize the data repository if the given URL points to a
        corresponding repository.

        Initializes a data repository object. This is done as part of
        a chain of responsibility. If the class cannot handle the given
        repository URL, it returns `None`. Otherwise a `DataRepository`
        instance is returned.

        Parameters
        ----------
        doi : str
            The DOI that identifies the repository
        archive_url : str
            The resolved URL for the DOI
        Nr`   )clsr   r   s      r   r   zDataRepository.initialize  s	    & tr   c                     t           )n  
        Use the repository API to get the download URL for a file given
        the archive URL.

        Parameters
        ----------
        file_name : str
            The name of the file in the archive that will be downloaded.

        Returns
        -------
        download_url : str
            The HTTP URL that can be used to download the file.
        NotImplementedError)r&   r   s     r   r   zDataRepository.download_url  s
      "!r   c                     t           )
        Populate the registry using the data repository's API

        Parameters
        ----------
        pooch : Pooch
            The pooch instance that the registry will be added to.
        r   )r&   rO   s     r   populate_registryz DataRepository.populate_registry  s
     "!r   N)r\   r]   r^   classmethodr   r   r   r`   r   r   r   r     sK          [(" " "$
" 
" 
" 
" 
"r   r   c                   f    e Zd ZdZd Zed             Zed             Zed             Z	d Z
d ZdS )	r   zhttps://zenodo.org/api/recordsc                 >    || _         || _        d | _        d | _        d S r   )r   r   _api_response_api_versionr&   r   r   s      r   r'   zZenodoRepository.__init__  s'    &! r   c                 T    t          |          }|d         dk    rdS  | ||          S )r   rl   z
zenodo.orgNr   r   r   r   parsed_archive_urls       r   r   zZenodoRepository.initialize  s9    ( '{33h'<774s3$$$r   c                     | j         addl}| j                            d          d         }|                    | j         d| t                                                    | _         | j         S )zCached API response from ZenodoNr   r   r   rk   )r   r9   r   r|   r:   base_api_urlr;   json)r&   r9   
article_ids      r   api_responsezZenodoRepository.api_response  s|     %OOO)//44R8J!)$33z33' ". " " dff 
 !!r   c                    | j         xt          d | j        d         D                       rd| _         nLt          d | j        d         D                       rd| _         n t          d| j         d| j         d	          | j         S )
aj  
        Version of the Zenodo API we are interacting with

        The versions can either be :

        - ``"legacy"``: corresponds to the Zenodo API that was supported until
          2023-10-12 (before the migration to InvenioRDM).
        - ``"new"``: corresponds to the new API that went online on 2023-10-13
          after the migration to InvenioRDM.

        The ``"new"`` API breaks backward compatibility with the ``"legacy"``
        one and could probably be replaced by an updated version that restores
        the behaviour of the ``"legacy"`` one.

        Returns
        -------
        str
        Nc              3      K   | ]}d |v V  	dS )keyNr`   .0files     r   	<genexpr>z/ZenodoRepository.api_version.<locals>.<genexpr>C  s&      HHT5D=HHHHHHr   fileslegacyc              3      K   | ]}d |v V  	dS )filenameNr`   r   s     r   r   z/ZenodoRepository.api_version.<locals>.<genexpr>E  s'      OODZ4'OOOOOOr   newz5Couldn't determine the version of the Zenodo API for  (doi:).)r   allr   r   r   r   r&   s    r   api_versionzZenodoRepository.api_version.  s    ( $HHT->w-GHHHHH $,!!OOD4Eg4NOOOOO $)!! <'< </3x< < <     r   c           	      4   | j         dk    rd | j        d         D             }nd | j        d         D             }||vr#t          d| d| j         d| j         d          | j         dk    r||         d	         d
         }n| j        d         }d| d| d}|S )a
  
        Use the repository API to get the download URL for a file given
        the archive URL.

        Parameters
        ----------
        file_name : str
            The name of the file in the archive that will be downloaded.

        Returns
        -------
        download_url : str
            The HTTP URL that can be used to download the file.

        Notes
        -----
        After Zenodo migrated to InvenioRDM on Oct 2023, their API changed. The
        link to the desired files that appears in the API response leads to 404
        errors (by 2023-10-17). The files are available in the following url:
        ``https://zenodo.org/records/{article_id}/files/{file_name}?download=1``.

        This method supports both the legacy and the new API.
        r   c                      i | ]}|d          |S )r   r`   r   items     r   
<dictcomp>z1ZenodoRepository.download_url.<locals>.<dictcomp>h  s    NNN4T%[$NNNr   r   c                     g | ]
}|d          S )r   r`   r   s     r   
<listcomp>z1ZenodoRepository.download_url.<locals>.<listcomp>j  s    MMM$T*%MMMr   File '' not found in data archive r   r   linksr&   idzhttps://zenodo.org/records/z/files/z?download=1)r   r   r   r   r   )r&   r   r   r   r   s        r   r   zZenodoRepository.download_urlN  s    2 x''NN43DW3MNNNEEMM$2CG2LMMMEE!!8 8 8#8 8+/88 8 8  
 x'' +G4V<LL*40JWjWWWWW  r   c                     | j         d         D ]/}|d         }| j        dk    rd}nd}d| }||j        ||         <   0dS )a  
        Populate the registry using the data repository's API

        Parameters
        ----------
        pooch : Pooch
            The pooch instance that the registry will be added to.

        Notes
        -----
        After Zenodo migrated to InvenioRDM on Oct 2023, their API changed. The
        checksums for each file listed in the API reference is now an md5 sum.

        This method supports both the legacy and the new API.
        r   checksumr   r   r   md5:N)r   r   registry)r&   rO   filedatar   r   s        r   r   z"ZenodoRepository.populate_registry{  si      )'2 	5 	5H
+H8++ ,(,,,4EN8C=))	5 	5r   N)r\   r]   r^   r   r'   r   r   propertyr   r   r   r   r`   r   r   r   r     s        3L! ! ! % % [%2 " " X" ! ! X!>+ + +Z5 5 5 5 5r   r   c                   R    e Zd Zd Zed             Zd Zed             Zd Z	d Z
dS )r   c                 0    || _         || _        d | _        d S r   r   r   r   r   s      r   r'   zFigshareRepository.__init__      &!r   c                 T    t          |          }|d         dk    rdS  | ||          S )r   rl   zfigshare.comNr   r   s       r   r   zFigshareRepository.initialize  s9    ( '{33h'>994s3$$$r   c                     | j                             d          \  }}|                    d          d         }|d         dk    rdS t          |dd                   }|S )zi
        Parse version from the doi

        Return None if version is not available in the doi.
        r   r   r   r   vNr   )r   r|   rF   )r&   _suffix	last_partversions        r   _parse_version_from_doiz*FigshareRepository._parse_version_from_doi  s_     HNN3''	6LL%%b)	Q<34im$$r   c                    | j         ddl}|                    d| j         t                                                    d         }|d         }|                                 }|)t          j        d| j         dt                     d| }nd| d	| }|                    |t                    }|
                                 |                                d
         | _         | j         S )z!Cached API response from FigshareNr   z)https://api.figshare.com/v2/articles?doi=rk   r   zThe Figshare DOI 'zv' doesn't specify which version of the repository should be used. Figshare will point to the latest version available.z%https://api.figshare.com/v2/articles/z
/versions/r   )r   r9   r:   r   r;   r   r   warningswarnUserWarningrD   )r&   r9   articler   r   api_urlrQ   s          r   r   zFigshareRepository.api_response  s)    %OOO llFDHFF' #   dffQG !J2244G  K K K K  	   O*NN
7!7 7-47 7 
  ||G_|EEH%%'''!)!9D!!r   c           	          d | j         D             }||vr#t          d| d| j         d| j         d          ||         d         }|S )r   c                      i | ]}|d          |S )namer`   r   s     r   r   z3FigshareRepository.download_url.<locals>.<dictcomp>  s    BBBftBBBr   r   r   r   r   r   )r   r   r   r   )r&   r   r   r   s       r   r   zFigshareRepository.download_url  st     CB0ABBBE!!ddd@PddX\X`ddd   Y'7r   c                 L    | j         D ]}d|d          |j        |d         <   dS )r   r   computed_md5r  N)r   r   r&   rO   r   s      r   r   z$FigshareRepository.populate_registry  sE     ) 	Q 	QH/Ph~6N/P/PEN8F+,,	Q 	Qr   N)r\   r]   r^   r'   r   r   r   r   r   r   r   r`   r   r   r   r     s        " " "
 % % [%2    (" (" X("T  .Q Q Q Q Qr   r   c                       e Zd Zd Zed             Zed             Zed             Zej	        d             Zd Z
d ZdS )	r   c                 0    || _         || _        d | _        d S r   r   r   s      r   r'   zDataverseRepository.__init__  r   r   c                     |                      ||          }d|j        cxk    rdk     rn ndS  | ||          }||_        |S )r   r   r   N)_get_api_responser>   r   )r   r   r   rQ   r   s        r   r   zDataverseRepository.initialize  sf    & ((k:: (&,,,,,,,,,4 Sk**
"*
r   c                     ddl }t          |          }|                    |d          d|d          d| t                    }|S )z
        Perform the actual API request

        This has been separated into a separate ``classmethod``, as it can be
        used prior and after the initialization.
        r   Nr   ://rl   z-/api/datasets/:persistentId?persistentId=doi:rk   )r9   r   r:   r;   )r   r   r   r9   parsedrQ   s         r   r  z%DataverseRepository._get_api_response9  sl     	;''<<j! 4 4fX&6 4 4.14 4#   
 

 r   c                 h    | j         %|                     | j        | j                  | _         | j         S )z-Cached API response from a DataVerse instance)r   r  r   r   r   s    r   r   z DataverseRepository.api_responseL  s:     %!%!7!7$*" "D !!r   c                     || _         dS )zUpdate the cached API responseN)r   )r&   rQ   s     r   r   z DataverseRepository.api_responseW  s     &r   c           	      .   t          | j                  }| j                                        }d |d         d         d         D             }||vr#t	          d| d| j         d| j         d          |d	          d
|d          d||         d          }|S )r   c                 8    i | ]}|d          d         |d          S )dataFiler   r`   r   s     r   r   z4DataverseRepository.download_url.<locals>.<dictcomp>n  s9     
 
 
 Z($z*:
 
 
r   ru   latestVersionr   r   r   r   r   r   r
  rl   z/api/access/datafile/r   )r   r   r   r   r   r   )r&   r   r  rQ   r   r   s         r   r   z DataverseRepository.download_url]  s     4+,,$))++
 
 (9'B
 
 
 E!!8 8 8#8 8+/88 8 8   j! ( (fX&6 ( (Y%( ( 	 r   c                     | j                                         d         d         d         D ]'}d|d         d          |j        |d         d         <   (dS )	r   ru   r  r   r   r  md5r   N)r   r   r   r  s      r   r   z%DataverseRepository.populate_registry~  si     )..008I'R 	 	H4x
+E244 N8J/
;<<	 	r   N)r\   r]   r^   r'   r   r   r  r   r   setterr   r   r`   r   r   r   r     s        " " "
   [:   [$ " " X" & & &
  B    r   r   rZ   )r_   r{   rH   rx   r   utilsr   r   ImportErrorr   r;   r   r   r   r   r   r   r   r   r   r   r   r`   r   r   <module>r     s    
			 



           DDDOOOO   HHH 4 4 4 4nj j j j j j j jZA A A A A A A AHl l l l l l l l^y5 y5 y5 y5 y5 y5 y5 y5x  82 2 2j2" 2" 2" 2" 2" 2" 2" 2"jV5 V5 V5 V5 V5~ V5 V5 V5r}Q }Q }Q }Q }Q }Q }Q }Q@v v v v v. v v v v vs   ! ++4 >>