
    -Ph~                         d Z ddlZddlZddlZddlmZ ddlZddlZddlm	Z	m
Z
 ddlmZmZmZmZmZmZmZ ddlmZmZmZ 	 	 	 	 	 dd	Z	 	 	 	 	 	 	 ddZ G d d          Zd ZddZdS )z5
The main Pooch class and a factory function for it.
    N)Path   )hash_matches	file_hash)check_version
get_loggermake_local_storagecache_locationtemporary_fileos_cacheunique_file_name)DOIDownloaderchoose_downloaderdoi_to_repositoryFc                 f   |t          d          }|t          |           }t          |dd          }|                                |z  }t	          ||          \  }}	|dv rt          |           t                                          d|	| t          |                     |t          | |          }t          | |||d           |<t                                          dt          t          |                               | |t          |          |d          S t          |          S )	a  
    Download and cache a single file locally.

    Uses HTTP or FTP by default, depending on the protocol in the given *url*.
    Other download methods can be controlled through the *downloader* argument
    (see below).

    The file will be downloaded to a temporary location first and its hash will
    be compared to the given *known_hash*. This is done to ensure that the
    download happened correctly and securely. If the hash doesn't match, the
    file will be deleted and an exception will be raised.

    If the file already exists locally, its hash will be compared to
    *known_hash*. If they are not the same, this is interpreted as the file
    needing to be updated and it will be downloaded again.

    You can bypass these checks by passing ``known_hash=None``. If this is
    done, the SHA256 hash of the downloaded file will be logged to the screen.
    It is highly recommended that you copy and paste this hash as *known_hash*
    so that future downloads are guaranteed to be the exact same file. This is
    crucial for reproducible computations.

    If the file exists in the given *path* with the given *fname* and the hash
    matches, it will not be downloaded and the absolute path to the file will
    be returned.

    .. note::

        This function is meant for downloading single files. If you need to
        manage the download and caching of several files, with versioning, use
        :func:`pooch.create` and :class:`pooch.Pooch` instead.

    Parameters
    ----------
    url : str
        The URL to the file that is to be downloaded. Ideally, the URL should
        end in a file name.
    known_hash : str or None
        A known hash (checksum) of the file. Will be used to verify the
        download or check if an existing file needs to be updated. By default,
        will assume it's a SHA256 hash. To specify a different hashing method,
        prepend the hash with ``algorithm:``, for example
        ``md5:pw9co2iun29juoh`` or ``sha1:092odwhi2ujdp2du2od2odh2wod2``. If
        None, will NOT check the hash of the downloaded file or check if an
        existing file needs to be updated.
    fname : str or None
        The name that will be used to save the file. Should NOT include the
        full path, just the file name (it will be appended to *path*). If
        None, will create a unique file name using a combination of the last
        part of the URL (assuming it's the file name) and the MD5 hash of the
        URL. For example, ``81whdo2d2e928yd1wi22-data-file.csv``. This ensures
        that files from different URLs never overwrite each other, even if they
        have the same name.
    path : str or PathLike or None
        The location of the cache folder on disk. This is where the file will
        be saved. If None, will save to a ``pooch`` folder in the default cache
        location for your operating system (see :func:`pooch.os_cache`).
    processor : None or callable
        If not None, then a function (or callable object) that will be called
        before returning the full path and after the file has been downloaded
        (if required). See :ref:`processors` for details.
    downloader : None or callable
        If not None, then a function (or callable object) that will be called
        to download a given URL to a provided local file name. See
        :ref:`downloaders` for details.
    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
    -------
    full_path : str
        The absolute path (including the file name) of the file in the local
        storage.

    Examples
    --------

    Download one of the data files from the Pooch repository on GitHub:

    >>> import os
    >>> from pooch import __version__, check_version, retrieve
    >>> # Make a URL for the version of pooch we have installed
    >>> url = "https://github.com/fatiando/pooch/raw/{}/data/tiny-data.txt"
    >>> url = url.format(check_version(__version__, fallback="main"))
    >>> # Download the file and save it locally. Will check the MD5 checksum of
    >>> # the downloaded file against the given value to make sure it's the
    >>> # right file. You can use other hashes by specifying different
    >>> # algorithm names (sha256, sha1, etc).
    >>> fname = retrieve(
    ...     url, known_hash="md5:70e2afd3fd7e336ae478b1e740a5f08e",
    ... )
    >>> with open(fname) as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> # Running again won't trigger a download and only return the path to
    >>> # the existing file.
    >>> fname2 = retrieve(
    ...     url, known_hash="md5:70e2afd3fd7e336ae478b1e740a5f08e",
    ... )
    >>> print(fname2 == fname)
    True
    >>> os.remove(fname)

    Files that are compressed with gzip, xz/lzma, or bzip2 can be automatically
    decompressed by passing using the :class:`pooch.Decompress` processor:

    >>> from pooch import Decompress
    >>> # URLs to a gzip compressed version of the data file.
    >>> url = ("https://github.com/fatiando/pooch/raw/{}/"
    ...        + "pooch/tests/data/tiny-data.txt.gz")
    >>> url = url.format(check_version(__version__, fallback="main"))
    >>> # By default, you would have to decompress the file yourself
    >>> fname = retrieve(
    ...     url,
    ...     known_hash="md5:8812ba10b6c7778014fdae81b03f9def",
    ... )
    >>> print(os.path.splitext(fname)[1])
    .gz
    >>> # Use the processor to decompress after download automatically and
    >>> # return the path to the decompressed file instead.
    >>> fname2 = retrieve(
    ...     url,
    ...     known_hash="md5:8812ba10b6c7778014fdae81b03f9def",
    ...     processor=Decompress(),
    ... )
    >>> print(fname2 == fname)
    False
    >>> with open(fname2) as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> os.remove(fname)
    >>> os.remove(fname2)

    When downloading archives (zip or tar), it can be useful to unpack them
    after download to avoid having to do that yourself. Use the processors
    :class:`pooch.Unzip` or :class:`pooch.Untar` to do this automatically:

    >>> from pooch import Unzip
    >>> # URLs to a zip archive with a single data file.
    >>> url = ("https://github.com/fatiando/pooch/raw/{}/"
    ...        + "pooch/tests/data/tiny-data.zip")
    >>> url = url.format(check_version(__version__, fallback="main"))
    >>> # By default, you would get the path to the archive
    >>> fname = retrieve(
    ...     url,
    ...     known_hash="md5:e9592cb46cf3514a1079051f8a148148",
    ... )
    >>> print(os.path.splitext(fname)[1])
    .zip
    >>> os.remove(fname)
    >>> # Using the processor, the archive will be unzipped and a list with the
    >>> # path to every file will be returned instead of a single path.
    >>> fnames = retrieve(
    ...     url,
    ...     known_hash="md5:e9592cb46cf3514a1079051f8a148148",
    ...     processor=Unzip(),
    ... )
    >>> # There was only a single file in our archive.
    >>> print(len(fnames))
    1
    >>> with open(fnames[0]) as f:
    ...     print(f.read().strip())
    # A tiny data file for test purposes only
    1  2  3  4  5  6
    >>> for f in fnames:
    ...     os.remove(f)


    Npooch)envversiondownloadupdatez%s data from '%s' to file '%s'.progressbar)r   zSHA256 hash of downloaded file: %s
Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.)r   r   r
   resolvedownload_actionr	   r   infostrr   stream_downloadr   )
url
known_hashfnamepath	processor
downloaderr   	full_pathactionverbs
             J/var/www/html/test/jupyter/venv/lib/python3.11/site-packages/pooch/core.pyretriever)      sG   n |  } %%$D$777D&I"9j99LFD''' 	4   -	NN		
 	
 	
 *3KHHHJY
JdKKKKLL" #i..))   yY666y>>    masterTc	                 j   |'t          ||          }|                    |          }t          | ||          } t          |t                    r6t
          j                            |d                                          dk    }|	                    d          dz   }t          | |||||          }	|	S )a  
    Create a :class:`~pooch.Pooch` with sensible defaults to fetch data files.

    If a version string is given, the Pooch will be versioned, meaning that the
    local storage folder and the base URL depend on the project version. This
    is necessary if your users have multiple versions of your library installed
    (using virtual environments) and you updated the data files between
    versions. Otherwise, every time a user switches environments would trigger
    a re-download of the data. The version string will be appended to the local
    storage path (for example, ``~/.mypooch/cache/v0.1``) and inserted into the
    base URL (for example,
    ``https://github.com/fatiando/pooch/raw/v0.1/data``). If the version string
    contains ``+XX.XXXXX``, it will be interpreted as a development version.

    Does **not** create the local data storage folder. The folder will only be
    created the first time a download is attempted with
    :meth:`pooch.Pooch.fetch`. This makes it safe to use this function at the
    module level (so it's executed on ``import`` and the resulting
    :class:`~pooch.Pooch` is a global variable).

    Parameters
    ----------
    path : str, PathLike, list or tuple
        The path to the local data storage folder. If this is a list or tuple,
        we'll join the parts with the appropriate separator. The *version* will
        be appended to the end of this path. Use :func:`pooch.os_cache` for a
        sensible default.
    base_url : str
        Base URL for the remote data source. All requests will be made relative
        to this URL. The string should have a ``{version}`` formatting mark in
        it. We will call ``.format(version=version)`` on this string. If the
        URL does not end in a ``'/'``, a trailing ``'/'`` will be added
        automatically.
    version : str or None
        The version string for your project. Should be PEP440 compatible. If
        None is given, will not attempt to format *base_url* and no subfolder
        will be appended to *path*.
    version_dev : str
        The name used for the development version of a project. If your data is
        hosted on Github (and *base_url* is a Github raw link), then
        ``"master"`` is a good choice (default). Ignored if *version* is None.
    env : str or None
        An environment variable that can be used to overwrite *path*. This
        allows users to control where they want the data to be stored. We'll
        append *version* to the end of this value as well.
    registry : dict or None
        A record of the files that are managed by this Pooch. Keys should be
        the file names and the values should be their hashes. Only files
        in the registry can be fetched from the local storage. Files in
        subdirectories of *path* **must use Unix-style separators** (``'/'``)
        even on Windows.
    urls : dict or None
        Custom URLs for downloading individual files in the registry. A
        dictionary with the file names as keys and the custom URLs as values.
        Not all files in *registry* need an entry in *urls*. If a file has an
        entry in *urls*, the *base_url* will be ignored when downloading it in
        favor of ``urls[fname]``.
    retry_if_failed : int
        Retry a file download the specified number of times if it fails because
        of a bad connection or a hash mismatch. By default, downloads are only
        attempted once (``retry_if_failed=0``). Initially, will wait for 1s
        between retries and then increase the wait time by 1s with each retry
        until a maximum of 10s.
    allow_updates : bool or str
        Whether existing files in local storage that have a hash mismatch with
        the registry are allowed to update from the remote URL. If a string is
        passed, we will assume it's the name of an environment variable that
        will be checked for the true/false value. If ``False``, any mismatch
        with hashes in the registry will result in an error. Defaults to
        ``True``.

    Returns
    -------
    pooch : :class:`~pooch.Pooch`
        The :class:`~pooch.Pooch` initialized with the given arguments.

    Examples
    --------

    Create a :class:`~pooch.Pooch` for a release (v0.1):

    >>> pup = create(path="myproject",
    ...              base_url="http://some.link.com/{version}/",
    ...              version="v0.1",
    ...              registry={"data.txt": "9081wo2eb2gc0u..."})
    >>> print(pup.path.parts)  # The path is a pathlib.Path
    ('myproject', 'v0.1')
    >>> # The local folder is only created when a dataset is first downloaded
    >>> print(pup.path.exists())
    False
    >>> print(pup.base_url)
    http://some.link.com/v0.1/
    >>> print(pup.registry)
    {'data.txt': '9081wo2eb2gc0u...'}
    >>> print(pup.registry_files)
    ['data.txt']

    If this is a development version (12 commits ahead of v0.1), then the
    ``version_dev`` will be used (defaults to ``"master"``):

    >>> pup = create(path="myproject",
    ...              base_url="http://some.link.com/{version}/",
    ...              version="v0.1+12.do9iwd")
    >>> print(pup.path.parts)
    ('myproject', 'master')
    >>> print(pup.base_url)
    http://some.link.com/master/

    Versioning is optional (but highly encouraged):

    >>> pup = create(path="myproject",
    ...              base_url="http://some.link.com/",
    ...              registry={"data.txt": "9081wo2eb2gc0u..."})
    >>> print(pup.path.parts)  # The path is a pathlib.Path
    ('myproject',)
    >>> print(pup.base_url)
    http://some.link.com/

    To place the storage folder at a subdirectory, pass in a list and we'll
    join the path for you using the appropriate separator for your operating
    system:

    >>> pup = create(path=["myproject", "cache", "data"],
    ...              base_url="http://some.link.com/{version}/",
    ...              version="v0.1")
    >>> print(pup.path.parts)
    ('myproject', 'cache', 'data', 'v0.1')

    The user can overwrite the storage path by setting an environment variable:

    >>> # The variable is not set so we'll use *path*
    >>> pup = create(path=["myproject", "not_from_env"],
    ...              base_url="http://some.link.com/{version}/",
    ...              version="v0.1",
    ...              env="MYPROJECT_DATA_DIR")
    >>> print(pup.path.parts)
    ('myproject', 'not_from_env', 'v0.1')
    >>> # Set the environment variable and try again
    >>> import os
    >>> os.environ["MYPROJECT_DATA_DIR"] = os.path.join("myproject", "env")
    >>> pup = create(path=["myproject", "not_env"],
    ...              base_url="http://some.link.com/{version}/",
    ...              version="v0.1",
    ...              env="MYPROJECT_DATA_DIR")
    >>> print(pup.path.parts)
    ('myproject', 'env', 'v0.1')

    N)fallback)r   truefalse/)r"   base_urlregistryurlsretry_if_failedallow_updates)r   formatr
   
isinstancer   osenvirongetlowerrstripPooch)
r"   r1   r   version_devr   r2   r3   r4   r5   pups
             r(   creater@      s    ~ +>>>??7?33 $W--D-%% Q
}f==CCEEPs##c)H
'#  C Jr*   c                   v    e Zd ZdZ	 	 	 	 ddZed             Zed             Zdd	Zd
 Z	d Z
d Zd ZddZdS )r=   a  
    Manager for a local data storage that can fetch from a remote source.

    Avoid creating ``Pooch`` instances directly. Use :func:`pooch.create`
    instead.

    Parameters
    ----------
    path : str
        The path to the local data storage folder. The path must exist in the
        file system.
    base_url : str
        Base URL for the remote data source. All requests will be made relative
        to this URL.
    registry : dict or None
        A record of the files that are managed by this good boy. Keys should be
        the file names and the values should be their hashes. Only files
        in the registry can be fetched from the local storage. Files in
        subdirectories of *path* **must use Unix-style separators** (``'/'``)
        even on Windows.
    urls : dict or None
        Custom URLs for downloading individual files in the registry. A
        dictionary with the file names as keys and the custom URLs as values.
        Not all files in *registry* need an entry in *urls*. If a file has an
        entry in *urls*, the *base_url* will be ignored when downloading it in
        favor of ``urls[fname]``.
    retry_if_failed : int
        Retry a file download the specified number of times if it fails because
        of a bad connection or a hash mismatch. By default, downloads are only
        attempted once (``retry_if_failed=0``). Initially, will wait for 1s
        between retries and then increase the wait time by 1s with each retry
        until a maximum of 10s.
    allow_updates : bool
        Whether existing files in local storage that have a hash mismatch with
        the registry are allowed to update from the remote URL. If ``False``,
        any mismatch with hashes in the registry will result in an error.
        Defaults to ``True``.

    Nr   Tc                     || _         || _        |i }|| _        |i }t          |          | _        || _        || _        d S N)r"   r1   r2   dictr3   r4   r5   )selfr"   r1   r2   r3   r4   r5   s          r(   __init__zPooch.__init__  sQ     	 H <DJJ	.*r*   c           	          t          t          j                            t          j                            t          | j                                                S )z"Absolute path to the local storage)r   r8   r"   abspath
expanduserr   rE   s    r(   rH   zPooch.abspath  s8     BGOOBG$6$6s49~~$F$FGGHHHr*   c                 *    t          | j                  S )z"List of file names on the registry)listr2   rJ   s    r(   registry_fileszPooch.registry_files  s     DM"""r*   Fc           	      V   |                      |           |                     |          }| j        |z  }| j        |         }t	          ||          \  }}	|dk    r| j        st          | d| d          |dv rt          t          | j                             t                      
                    d|	||t          | j                             |t          ||          }t          ||||| | j                   | |t          |          ||           S t          |          S )	a*
  
        Get the absolute path to a file in the local storage.

        If it's not in the local storage, it will be downloaded. If the hash of
        the file in local storage doesn't match the one in the registry, will
        download a new copy of the file. This is considered a sign that the
        file was updated in the remote storage. If the hash of the downloaded
        file still doesn't match the one in the registry, will raise an
        exception to warn of possible file corruption.

        Post-processing actions sometimes need to be taken on downloaded files
        (unzipping, conversion to a more efficient format, etc). If these
        actions are time or memory consuming, it would be best to do this only
        once right after the file is downloaded. Use the *processor* argument
        to specify a function that is executed after the download to perform
        these actions. See :ref:`processors` for details.

        Custom file downloaders can be provided through the *downloader*
        argument. By default, Pooch will determine the download protocol from
        the URL in the registry. If the server for a given file requires
        authentication (username and password), use a downloader that support
        these features. Downloaders can also be used to print custom messages
        (like a progress bar), etc. See :ref:`downloaders` for details.

        Parameters
        ----------
        fname : str
            The file name (relative to the *base_url* of the remote data
            storage) to fetch from the local storage.
        processor : None or callable
            If not None, then a function (or callable object) that will be
            called before returning the full path and after the file has been
            downloaded. See :ref:`processors` for details.
        downloader : None or callable
            If not None, then a function (or callable object) that will be
            called to download a given URL to a provided local file name. See
            :ref:`downloaders` for details.
        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
        -------
        full_path : str
            The absolute path (including the file name) of the file in the
            local storage.

        r   z needs to update z but updates are disallowed.r   z%s file '%s' from '%s' to '%s'.Nr   )r   r4   )_assert_file_in_registryget_urlrH   r2   r   r5   
ValueErrorr	   r   r   r   r   r   r4   )
rE   r!   r#   r$   r   r   r%   r    r&   r'   s
             r(   fetchzPooch.fetch  s_   f 	%%e,,,ll5!!L5(	]5)
&y*==Xd&8RR9RRR   +++ s4<00111LL1DL!!   !.sLLL
 $ 4     9S^^VT:::9~~r*   c                 >    || j         vrt          d| d          dS )zg
        Check if a file is in the registry and raise :class:`ValueError` if
        it's not.
        zFile 'z' is not in the registry.N)r2   rQ   rE   r!   s     r(   rO   zPooch._assert_file_in_registry[  s3    
 %%FeFFFGGG &%r*   c                     |                      |           | j                            |d                    | j        |g                    S )a  
        Get the full URL to download a file in the registry.

        Parameters
        ----------
        fname : str
            The file name (relative to the *base_url* of the remote data
            storage) to fetch from the local storage.

         )rO   r3   r:   joinr1   rT   s     r(   rP   zPooch.get_urlc  sA     	%%e,,,y}}UBGGT]E,B$C$CDDDr*   c                    t          j                    5 }t          |d          r|}n$|                    t	          |d                    }t          |          D ]\  }}t          |t                    r|                    d          }|	                                }|
                    d          rYt          j        |          }t          |          dvr,t          d| d|dz    d	t          |           d
| d	          |rQ|d         }|d         }t          |          dk    r|d         }	|	| j        |<   |                                | j        |<   	 ddd           dS # 1 swxY w Y   dS )a  
        Load entries from a file and add them to the registry.

        Use this if you are managing many files.

        Each line of the file should have file name and its hash separated by
        a space. Hash can specify checksum algorithm using "alg:hash" format.
        In case no algorithm is provided, SHA256 is used by default.
        Only one file per line is allowed. Custom download URLs for individual
        files can be specified as a third element on the line. Line comments
        can be added and must be prepended with ``#``.

        Parameters
        ----------
        fname : str | fileobj
            Path (or open file object) to the registry file.

        readzutf-8)encoding#)r         z&Invalid entry in Pooch registry file 'z$': expected 2 or 3 elements in line r   z	 but got z. Offending entry: ''r   r]   r\   N)
contextlib	ExitStackhasattrenter_contextopen	enumerater7   bytesdecodestrip
startswithshlexsplitlenOSErrorr3   r;   r2   )
rE   r!   stackfinlinenumlineelements	file_namefile_checksumfile_urls
             r(   load_registryzPooch.load_registryq  s
   & !## 	Euuf%% I ))$uw*G*G*GHH!*3 E EdE** 0;;w//Dzz||??3''  ;t,,8}}	11!F F F<CaKF Fx==F F>BF F F  
  E (I$,QKM8}}))#+A;/7	),/</B/B/D/DDM),-E	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	E 	Es   EE''E+.E+c                    t          | j                  }t          |t                    st	          d| j         ddz             | j                            dd          }t          |          }|                    |           S )a  
        Populate the registry using the data repository API

        Fill the registry with all the files available in the data repository,
        along with their hashes. It will make a request to the data repository
        API to retrieve this information. No file is downloaded during this
        process.

        .. important::

            This method is intended to be used only when the ``base_url`` is
            a DOI.
        zInvalid base_url 'z': z9Pooch.load_registry_from_doi is only implemented for DOIszdoi:rV   )r   r1   r7   r   rQ   replacer   populate_registry)rE   r$   doi
repositorys       r(   load_registry_from_doizPooch.load_registry_from_doi  s      't}55
*m44 	7T]777MN   m##FB//&s++
 ++D111r*   c                    |                      |           |                     |          }|t          |          }	  ||d| d          }n5# t          $ r(}dt	          |           d}t          |          |d}~ww xY w|S )a  
        Check availability of a remote file without downloading it.

        Use this method when working with large files to check if they are
        available for download.

        Parameters
        ----------
        fname : str
            The file name (relative to the *base_url* of the remote data
            storage).
        downloader : None or callable
            If not None, then a function (or callable object) that will be
            called to check the availability of the file on the server. See
            :ref:`downloaders` for details.

        Returns
        -------
        status : bool
            True if the file is available for download. False otherwise.

        NT)
check_onlyzDownloader 'z'' does not support availability checks.)rO   rP   r   	TypeErrorr   NotImplementedError)rE   r!   r$   r   	availableerror	error_msgs          r(   is_availablezPooch.is_available  s    . 	%%e,,,ll5!!*3//J	<"
3dtDDDII 	< 	< 	<Ws:WWW  &i00e;		<
 s   A 
A?#A::A?)NNr   T)NNFrC   )__name__
__module____qualname____doc__rF   propertyrH   rM   rR   rO   rP   ru   r{   r    r*   r(   r=   r=     s        & &X + + + +( I I XI # # X#[ [ [ [zH H HE E E1E 1E 1Ef2 2 2<" " " " " "r*   r=   c                     |                                  sd}d}n&t          t          |           |          sd}d}nd}d}||fS )a  
    Determine the action that is needed to get the file on disk.

    Parameters
    ----------
    path : PathLike
        The path to the file on disk.
    known_hash : str
        A known hash (checksum) of the file. Will be used to verify the
        download or check if an existing file needs to be updated. By default,
        will assume it's a SHA256 hash. To specify a different hashing method,
        prepend the hash with ``algorithm:``, for example
        ``md5:pw9co2iun29juoh`` or ``sha1:092odwhi2ujdp2du2od2odh2wod2``.

    Returns
    -------
    action, verb : str
        The action that must be taken and the English verb (infinitive form of
        *action*) used in the log:
        * ``'download'``: File does not exist locally and must be downloaded.
        * ``'update'``: File exists locally but needs to be updated.
        * ``'fetch'``: File exists locally and only need to inform its path.


    r   Downloadingr   UpdatingrR   Fetching)existsr   r   )r"   r    r&   r'   s       r(   r   r     sX    4 ;;== #d))Z00 4<r*   c           
         ddl }|j                                        s&t          j        t          |j                             d|z   }d}t          |          D ]%}		 t          t          |j                            5 }
 || |
|           t          |
|dt          |j	                             t          j        |
t          |                     ddd           n# 1 swxY w Y    dS # t          |j        j        f$ ry |	|dz
  k    r ||	dz   z
  }t                                          dt          |j	                  ||dk    rd	nd
           t#          j        t'          |	dz   |                     Y #w xY wdS )a  
    Stream the file and check that its hash matches the known one.

    The file is first downloaded to a temporary file name in the cache folder.
    It will be moved to the desired file name only if the hash matches the
    known hash. Otherwise, the temporary file is deleted.

    If the download fails for either a bad connection or a hash mismatch, we
    will retry the download the specified number of times in case the failure
    was due to a network error.
    r   Nr   
   )r"   T)strictsourcezHFailed to download '%s'. Will attempt the download again %d more time%s.srV   )requests.exceptionsparentr   r8   makedirsr   ranger   r   nameshutilmoverQ   
exceptionsRequestExceptionr   r   timesleepmin)r   r!   r    r$   r   r4   requestsdownload_attemptsmax_waititmpretries_lefts               r(   r   r     s     <   '
C%%&&&O+H$%% - -	-  S%6%6777 -3
3U+++S*T#ej//RRRRCU,,,- - - - - - - - - - - - - - - EEH/@A 	- 	- 	-%))),A6LLLBEJ#a''R   Js1q5(++,,,,,	-- -s8   "C/ AC!C/!C%	%C/(C%	)C//BE>=E>)NNNNF)Nr+   NNNr   T)Nr   )r   r8   r   r_   pathlibr   ri   r   hashesr   r   utilsr   r   r	   r
   r   r   r   downloadersr   r   r   r)   r@   r=   r   r   r   r*   r(   <module>r      s    
			              , + + + + + + +                  M L L L L L L L L L 	^ ^ ^ ^H 	t t t tnm m m m m m m m`	# # #L)- )- )- )- )- )-r*   