#!/bin/python3

# -*- coding: utf-8 -*-
#==============================
#    Author: <NAME>
#    Last modified: 2018-06-29 14:48
#    Filename: downloader.py
#    Description:
#    
#=============================#
# change from keras.utils

import hashlib
import os
import gzip
import tarfile
import zipfile
import gzip
import six
import re
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError
from six.moves.urllib.request import urlopen
from .generic_utils import Progbar

try:
#     from urllib.request import urlretrieve
    from six.moves.urllib.request import urlretrieve
except ImportError:
    from urllib import urlretrieve  # py2
try:
    from urllib.parse import urljoin
except ImportError:
    from urlparse import urljoin

DEFAULT_DIR = '/tmp/datasets'

def get_dataset(urls=None, base_url=None, filenames=None, directory=None, md5_hashs=None, extract=False):
    """get_dataset(urls=None, base_url=None, filenames=None, directory=DEFAULT_DIR):
    download dataset from urls or base_url + filenames relatively.

    arguements
    ------------
    urls: The urls to be downloaded.
    base_url: The base url of each filenames.
    filenames: Using with base_url, the files to be downloaded.
    directory: The directory path to store the dataset. If not exists, it would be created.
               It would set to '/tmp/datasets' by default.
    """
    if directory is None:
        directory = DEFAULT_DIR

    if os.path.exists(directory) is False:
        os.makedirs(directory)

    if urls is None and ( base_url and filenames ) is not None:
        urls = list()
        for filename in filenames:
            urls.append(base_url + filename)

    if isinstance(urls, str):
        urls = [urls]

    if  md5_hashs is None:
        md5_hashs = [None] * len(urls)
    
    fpaths = list()
    for url, md5_hash in zip(urls, md5_hashs):
        fpath = download(url, directory, md5_hash, extract=extract)
        fpaths.append(fpath)
    return fpaths

def download(url,
             directory,
             md5_hash=None,
             file_hash=None,
             hash_algorithm='auto',
             extract=False,
             archive_format='auto'):

    filename = os.path.basename(url)
    fpath = os.path.join(directory, filename)

    download = False
    if os.path.exists(fpath):
        # File found; verify integrity if a hash was provided.
        if file_hash is not None:
            if not validate_file(fpath, file_hash, algorithm=hash_algorithm):
                print('A local file was found, but it seems to be '
                      'incomplete or outdated because the ' + hash_algorithm +
                      ' file hash does not match the original value of ' +
                      file_hash + ' so we will re-download the data.')
                download = True
    else:
        download = True

    if download:

        class ProgressTracker(object):
            # Maintain progbar for the lifetime of download.
            # This design was chosen for Python 2.7 compatibility.
            progbar = None

        def dl_progress(count, block_size, total_size):
            if ProgressTracker.progbar is None:
                if total_size is -1:
                    total_size = None
                ProgressTracker.progbar = Progbar(total_size)
            else:
                ProgressTracker.progbar.update(count * block_size)

        print('Downloading data from {} to directory {}'.format(url, fpath))

        error_msg = 'URL fetch failure on {}: {} -- {}'
        try:
            try:
                urlretrieve(url, fpath, dl_progress)
            except URLError as e:
                raise Exception(error_msg.format(url, e.errno, e.reason))
            except HTTPError as e:
                raise Exception(error_msg.format(url, e.code, e.msg))
        except (Exception, KeyboardInterrupt) as e:
            if os.path.exists(fpath):
                os.remove(fpath)
            raise
        ProgressTracker.progbar = None

    if extract:
        ret = _extract_archive(fpath, directory, archive_format)
#         if ret is True:
#             print("extracted to", directory)
#         else:
#             print("extracting failed!")


    return fpath

def _hash_file(fpath, algorithm='sha256', chunk_size=65535):
    """Calculates a file sha256 or md5 hash.

    # Example

    ```python
        >>> from keras.data_utils import _hash_file
        >>> _hash_file('/path/to/file.zip')
        'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
    ```

    # Arguments
        fpath: path to the file being validated
        algorithm: hash algorithm, one of 'auto', 'sha256', or 'md5'.
            The default 'auto' detects the hash algorithm in use.
        chunk_size: Bytes to read at a time, important for large files.

    # Returns
        The file hash
    """
    if (algorithm is 'sha256') or (algorithm is 'auto' and len(hash) is 64):
        hasher = hashlib.sha256()
    else:
        hasher = hashlib.md5()

    with open(fpath, 'rb') as fpath_file:
        for chunk in iter(lambda: fpath_file.read(chunk_size), b''):
            hasher.update(chunk)

    return hasher.hexdigest()


def validate_file(fpath, file_hash, algorithm='auto', chunk_size=65535):
    """Validates a file against a sha256 or md5 hash.

    # Arguments
        fpath: path to the file being validated
        file_hash:  The expected hash string of the file.
            The sha256 and md5 hash algorithms are both supported.
        algorithm: Hash algorithm, one of 'auto', 'sha256', or 'md5'.
            The default 'auto' detects the hash algorithm in use.
        chunk_size: Bytes to read at a time, important for large files.

    # Returns
        Whether the file is valid
    """
    if ((algorithm is 'sha256') or
            (algorithm is 'auto' and len(file_hash) is 64)):
        hasher = 'sha256'
    else:
        hasher = 'md5'

    if str(_hash_file(fpath, hasher, chunk_size)) == str(file_hash):
        return True
    else:
        return False

def _extract_archive(file_path, path='.', archive_format='auto'):
    """Extracts an archive if it matches tar, tar.gz, tar.bz, or zip formats.

    # Arguments
        file_path: path to the archive file
        path: path to extract the archive file
        archive_format: Archive format to try for extracting the file.
            Options are 'auto', 'tar', 'zip', and None.
            'tar' includes tar, tar.gz, and tar.bz files.
            The default 'auto' is ['tar', 'zip'].
            None or an empty list will return no matches found.

    # Returns
        True if a match was found and an archive extraction was completed,
        False otherwise.
    """
    if archive_format is None:
        return False
    if archive_format is 'auto':
        archive_format = ['tar', 'zip']
    if isinstance(archive_format, six.string_types):
        archive_format = [archive_format]

    for archive_type in archive_format:
        if archive_type is 'tar':
            open_fn = tarfile.open
            is_match_fn = tarfile.is_tarfile
        if archive_type is 'zip':
            open_fn = zipfile.ZipFile
            is_match_fn = zipfile.is_zipfile

        if is_match_fn(file_path):
            with open_fn(file_path) as archive:
                # check weather extracted or not
                extracted = True
                for fname in archive.getnames():
                    if not os.path.exists(os.path.join(path, fname)):
                        extracted = False
                if not extracted:
                    try:
                        archive.extractall(path)
                        print('extracted to', path)
                    except (tarfile.TarError, RuntimeError,
                            KeyboardInterrupt):
                        if os.path.exists(path):
                            if os.path.isfile(path):
                                os.remove(path)
                            else:
                                shutil.rmtree(path)
                        raise
            return True
    return False

def get_file(origin,
             fname=None,
#              untar=False,
             md5_hash=None,
             file_hash=None,
             cache_dir=None,
             cache_subdir=None,
             hash_algorithm='auto',
             extract=False,
             archive_format='auto'):
    """Downloads a file from a URL if it not already in the cache.

    By default the file at the url `origin` is downloaded to the
    cache_dir `/tmp/datasets`

    Files in tar, tar.gz, tar.bz, and zip formats can also be extracted.
    Passing a hash will verify the file after download. The command line
    programs `shasum` and `sha256sum` can compute the hash.

    # Arguments
        origin: Original URL of the file.
        fname: Name of the file. If an absolute path `/path/to/file.txt` is
            specified the file will be saved at that location.
            By default fname will remain it's original name.
        md5_hash: Deprecated in favor of 'file_hash'.
            md5 hash of the file for verification
        file_hash: The expected hash string of the file after download.
            The sha256 and md5 hash algorithms are both supported.
        cache_dir: Location to store cached files, when None it
            defaults to /tmp/datasets
        cache_subdir: Subdirectory under the cache_dir where the file is
            saved. If an absolute path `/path/to/folder` is
            specified the file will be saved at that location.
        hash_algorithm: Select the hash algorithm to verify the file.
            options are 'md5', 'sha256', and 'auto'.
            The default 'auto' detects the hash algorithm in use.
        extract: True tries extracting the file as an Archive, like tar or zip.
        archive_format: Archive format to try for extracting the file.
            Options are 'auto', 'tar', 'zip', and None.
            'tar' includes tar, tar.gz, and tar.bz files.
            The default 'auto' is ['tar', 'zip'].
            None or an empty list will return no matches found.

    # Returns
        Path to the downloaded file
    """

    if fname is None:
        fname = os.path.basename(origin)
        if fname == '':
            raise Exception("Please specify fname")

    if md5_hash is not None and file_hash is None:
        file_hash = md5_hash
        hash_algorithm = 'md5'

    if cache_dir is None:
        cache_dir = '/tmp/datasets'

    if not os.path.exists(cache_dir):
        os.makedirs(cache_dir)
    if not os.access(cache_dir, os.W_OK):
        raise Exception("Can't write to {}".format(cache_dir))
    if cache_subdir is not None:
        datadir = os.path.join(cache_dir, cache_subdir)
    else:
        datadir = cache_dir
    if not os.path.exists(datadir):
        os.makedirs(datadir)

    fpath = os.path.join(datadir, fname)

    download = False
    if os.path.exists(fpath):
        # File found; verify integrity if a hash was provided.
        if file_hash is not None:
            if not validate_file(fpath, file_hash, algorithm=hash_algorithm):
                print('A local file was found, but it seems to be '
                      'incomplete or outdated because the ' + hash_algorithm +
                      ' file hash does not match the original value of ' +
                      file_hash + ' so we will re-download the data.')
                download = True
    else:
        download = True

    if download:
        print('Downloading data from', origin)

        class ProgressTracker(object):
            # Maintain progbar for the lifetime of download.
            # This design was chosen for Python 2.7 compatibility.
            progbar = None

        def dl_progress(count, block_size, total_size):
            if ProgressTracker.progbar is None:
                if total_size is -1:
                    total_size = None
                ProgressTracker.progbar = Progbar(total_size)
            else:
                ProgressTracker.progbar.update(count * block_size)

        error_msg = 'URL fetch failure on {}: {} -- {}'
        try:
            try:
                urlretrieve(origin, fpath, dl_progress)
            except URLError as e:
                raise Exception(error_msg.format(origin, e.errno, e.reason))
            except HTTPError as e:
                raise Exception(error_msg.format(origin, e.code, e.msg))
        except (Exception, KeyboardInterrupt) as e:
            if os.path.exists(fpath):
                os.remove(fpath)
            raise
        ProgressTracker.progbar = None

    if extract:
        _extract_archive(fpath, datadir, archive_format)

    return fpath

#!/bin/python3

# -*- coding: utf-8 -*-
#==============================
#    Author: <NAME>
#    Last modified: 2018-06-29 14:48
#    Filename: downloader.py
#    Description:
#    
#=============================#
# change from keras.utils

import hashlib
import os
import gzip
import tarfile
import zipfile
import gzip
import six
import re
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError
from six.moves.urllib.request import urlopen
from .generic_utils import Progbar

try:
#     from urllib.request import urlretrieve
    from six.moves.urllib.request import urlretrieve
except ImportError:
    from urllib import urlretrieve  # py2
try:
    from urllib.parse import urljoin
except ImportError:
    from urlparse import urljoin

DEFAULT_DIR = '/tmp/datasets'

def get_dataset(urls=None, base_url=None, filenames=None, directory=None, md5_hashs=None, extract=False):
    """get_dataset(urls=None, base_url=None, filenames=None, directory=DEFAULT_DIR):
    download dataset from urls or base_url + filenames relatively.

    arguements
    ------------
    urls: The urls to be downloaded.
    base_url: The base url of each filenames.
    filenames: Using with base_url, the files to be downloaded.
    directory: The directory path to store the dataset. If not exists, it would be created.
               It would set to '/tmp/datasets' by default.
    """
    if directory is None:
        directory = DEFAULT_DIR

    if os.path.exists(directory) is False:
        os.makedirs(directory)

    if urls is None and ( base_url and filenames ) is not None:
        urls = list()
        for filename in filenames:
            urls.append(base_url + filename)

    if isinstance(urls, str):
        urls = [urls]

    if  md5_hashs is None:
        md5_hashs = [None] * len(urls)
    
    fpaths = list()
    for url, md5_hash in zip(urls, md5_hashs):
        fpath = download(url, directory, md5_hash, extract=extract)
        fpaths.append(fpath)
    return fpaths

def download(url,
             directory,
             md5_hash=None,
             file_hash=None,
             hash_algorithm='auto',
             extract=False,
             archive_format='auto'):

    filename = os.path.basename(url)
    fpath = os.path.join(directory, filename)

    download = False
    if os.path.exists(fpath):
        # File found; verify integrity if a hash was provided.
        if file_hash is not None:
            if not validate_file(fpath, file_hash, algorithm=hash_algorithm):
                print('A local file was found, but it seems to be '
                      'incomplete or outdated because the ' + hash_algorithm +
                      ' file hash does not match the original value of ' +
                      file_hash + ' so we will re-download the data.')
                download = True
    else:
        download = True

    if download:

        class ProgressTracker(object):
            # Maintain progbar for the lifetime of download.
            # This design was chosen for Python 2.7 compatibility.
            progbar = None

        def dl_progress(count, block_size, total_size):
            if ProgressTracker.progbar is None:
                if total_size is -1:
                    total_size = None
                ProgressTracker.progbar = Progbar(total_size)
            else:
                ProgressTracker.progbar.update(count * block_size)

        print('Downloading data from {} to directory {}'.format(url, fpath))

        error_msg = 'URL fetch failure on {}: {} -- {}'
        try:
            try:
                urlretrieve(url, fpath, dl_progress)
            except URLError as e:
                raise Exception(error_msg.format(url, e.errno, e.reason))
            except HTTPError as e:
                raise Exception(error_msg.format(url, e.code, e.msg))
        except (Exception, KeyboardInterrupt) as e:
            if os.path.exists(fpath):
                os.remove(fpath)
            raise
        ProgressTracker.progbar = None

    if extract:
        ret = _extract_archive(fpath, directory, archive_format)
#         if ret is True:
#             print("extracted to", directory)
#         else:
#             print("extracting failed!")


    return fpath

def _hash_file(fpath, algorithm='sha256', chunk_size=65535):
    """Calculates a file sha256 or md5 hash.

    # Example

    ```python
        >>> from keras.data_utils import _hash_file
        >>> _hash_file('/path/to/file.zip')
        'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
    ```

    # Arguments
        fpath: path to the file being validated
        algorithm: hash algorithm, one of 'auto', 'sha256', or 'md5'.
            The default 'auto' detects the hash algorithm in use.
        chunk_size: Bytes to read at a time, important for large files.

    # Returns
        The file hash
    """
    if (algorithm is 'sha256') or (algorithm is 'auto' and len(hash) is 64):
        hasher = hashlib.sha256()
    else:
        hasher = hashlib.md5()

    with open(fpath, 'rb') as fpath_file:
        for chunk in iter(lambda: fpath_file.read(chunk_size), b''):
            hasher.update(chunk)

    return hasher.hexdigest()


def validate_file(fpath, file_hash, algorithm='auto', chunk_size=65535):
    """Validates a file against a sha256 or md5 hash.

    # Arguments
        fpath: path to the file being validated
        file_hash:  The expected hash string of the file.
            The sha256 and md5 hash algorithms are both supported.
        algorithm: Hash algorithm, one of 'auto', 'sha256', or 'md5'.
            The default 'auto' detects the hash algorithm in use.
        chunk_size: Bytes to read at a time, important for large files.

    # Returns
        Whether the file is valid
    """
    if ((algorithm is 'sha256') or
            (algorithm is 'auto' and len(file_hash) is 64)):
        hasher = 'sha256'
    else:
        hasher = 'md5'

    if str(_hash_file(fpath, hasher, chunk_size)) == str(file_hash):
        return True
    else:
        return False

def _extract_archive(file_path, path='.', archive_format='auto'):
    """Extracts an archive if it matches tar, tar.gz, tar.bz, or zip formats.

    # Arguments
        file_path: path to the archive file
        path: path to extract the archive file
        archive_format: Archive format to try for extracting the file.
            Options are 'auto', 'tar', 'zip', and None.
            'tar' includes tar, tar.gz, and tar.bz files.
            The default 'auto' is ['tar', 'zip'].
            None or an empty list will return no matches found.

    # Returns
        True if a match was found and an archive extraction was completed,
        False otherwise.
    """
    if archive_format is None:
        return False
    if archive_format is 'auto':
        archive_format = ['tar', 'zip']
    if isinstance(archive_format, six.string_types):
        archive_format = [archive_format]

    for archive_type in archive_format:
        if archive_type is 'tar':
            open_fn = tarfile.open
            is_match_fn = tarfile.is_tarfile
        if archive_type is 'zip':
            open_fn = zipfile.ZipFile
            is_match_fn = zipfile.is_zipfile

        if is_match_fn(file_path):
            with open_fn(file_path) as archive:
                # check weather extracted or not
                extracted = True
                for fname in archive.getnames():
                    if not os.path.exists(os.path.join(path, fname)):
                        extracted = False
                if not extracted:
                    try:
                        archive.extractall(path)
                        print('extracted to', path)
                    except (tarfile.TarError, RuntimeError,
                            KeyboardInterrupt):
                        if os.path.exists(path):
                            if os.path.isfile(path):
                                os.remove(path)
                            else:
                                shutil.rmtree(path)
                        raise
            return True
    return False

def get_file(origin,
             fname=None,
#              untar=False,
             md5_hash=None,
             file_hash=None,
             cache_dir=None,
             cache_subdir=None,
             hash_algorithm='auto',
             extract=False,
             archive_format='auto'):
    """Downloads a file from a URL if it not already in the cache.

    By default the file at the url `origin` is downloaded to the
    cache_dir `/tmp/datasets`

    Files in tar, tar.gz, tar.bz, and zip formats can also be extracted.
    Passing a hash will verify the file after download. The command line
    programs `shasum` and `sha256sum` can compute the hash.

    # Arguments
        origin: Original URL of the file.
        fname: Name of the file. If an absolute path `/path/to/file.txt` is
            specified the file will be saved at that location.
            By default fname will remain it's original name.
        md5_hash: Deprecated in favor of 'file_hash'.
            md5 hash of the file for verification
        file_hash: The expected hash string of the file after download.
            The sha256 and md5 hash algorithms are both supported.
        cache_dir: Location to store cached files, when None it
            defaults to /tmp/datasets
        cache_subdir: Subdirectory under the cache_dir where the file is
            saved. If an absolute path `/path/to/folder` is
            specified the file will be saved at that location.
        hash_algorithm: Select the hash algorithm to verify the file.
            options are 'md5', 'sha256', and 'auto'.
            The default 'auto' detects the hash algorithm in use.
        extract: True tries extracting the file as an Archive, like tar or zip.
        archive_format: Archive format to try for extracting the file.
            Options are 'auto', 'tar', 'zip', and None.
            'tar' includes tar, tar.gz, and tar.bz files.
            The default 'auto' is ['tar', 'zip'].
            None or an empty list will return no matches found.

    # Returns
        Path to the downloaded file
    """

    if fname is None:
        fname = os.path.basename(origin)
        if fname == '':
            raise Exception("Please specify fname")

    if md5_hash is not None and file_hash is None:
        file_hash = md5_hash
        hash_algorithm = 'md5'

    if cache_dir is None:
        cache_dir = '/tmp/datasets'

    if not os.path.exists(cache_dir):
        os.makedirs(cache_dir)
    if not os.access(cache_dir, os.W_OK):
        raise Exception("Can't write to {}".format(cache_dir))
    if cache_subdir is not None:
        datadir = os.path.join(cache_dir, cache_subdir)
    else:
        datadir = cache_dir
    if not os.path.exists(datadir):
        os.makedirs(datadir)

    fpath = os.path.join(datadir, fname)

    download = False
    if os.path.exists(fpath):
        # File found; verify integrity if a hash was provided.
        if file_hash is not None:
            if not validate_file(fpath, file_hash, algorithm=hash_algorithm):
                print('A local file was found, but it seems to be '
                      'incomplete or outdated because the ' + hash_algorithm +
                      ' file hash does not match the original value of ' +
                      file_hash + ' so we will re-download the data.')
                download = True
    else:
        download = True

    if download:
        print('Downloading data from', origin)

        class ProgressTracker(object):
            # Maintain progbar for the lifetime of download.
            # This design was chosen for Python 2.7 compatibility.
            progbar = None

        def dl_progress(count, block_size, total_size):
            if ProgressTracker.progbar is None:
                if total_size is -1:
                    total_size = None
                ProgressTracker.progbar = Progbar(total_size)
            else:
                ProgressTracker.progbar.update(count * block_size)

        error_msg = 'URL fetch failure on {}: {} -- {}'
        try:
            try:
                urlretrieve(origin, fpath, dl_progress)
            except URLError as e:
                raise Exception(error_msg.format(origin, e.errno, e.reason))
            except HTTPError as e:
                raise Exception(error_msg.format(origin, e.code, e.msg))
        except (Exception, KeyboardInterrupt) as e:
            if os.path.exists(fpath):
                os.remove(fpath)
            raise
        ProgressTracker.progbar = None

    if extract:
        _extract_archive(fpath, datadir, archive_format)

    return fpath

#!/bin/python3 # -*- coding: utf-8 -*- #============================== #    Author: <NAME> #    Last modified: 2018-06-29 14:48 #    Filename: downloader.py #    Description: # #=============================# # change from keras.utils #     from urllib.request import urlretrieve # py2 get_dataset(urls=None, base_url=None, filenames=None, directory=DEFAULT_DIR):     download dataset from urls or base_url + filenames relatively.      arguements     ------------     urls: The urls to be downloaded.     base_url: The base url of each filenames.     filenames: Using with base_url, the files to be downloaded.     directory: The directory path to store the dataset. If not exists, it would be created.                It would set to '/tmp/datasets' by default. # File found; verify integrity if a hash was provided. # Maintain progbar for the lifetime of download. # This design was chosen for Python 2.7 compatibility. #         if ret is True: #             print("extracted to", directory) #         else: #             print("extracting failed!") Calculates a file sha256 or md5 hash.      # Example      ```python         >>> from keras.data_utils import _hash_file         >>> _hash_file('/path/to/file.zip')         'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'     ```      # Arguments         fpath: path to the file being validated         algorithm: hash algorithm, one of 'auto', 'sha256', or 'md5'.             The default 'auto' detects the hash algorithm in use.         chunk_size: Bytes to read at a time, important for large files.      # Returns         The file hash Validates a file against a sha256 or md5 hash.      # Arguments         fpath: path to the file being validated         file_hash:  The expected hash string of the file.             The sha256 and md5 hash algorithms are both supported.         algorithm: Hash algorithm, one of 'auto', 'sha256', or 'md5'.             The default 'auto' detects the hash algorithm in use.         chunk_size: Bytes to read at a time, important for large files.      # Returns         Whether the file is valid Extracts an archive if it matches tar, tar.gz, tar.bz, or zip formats.      # Arguments         file_path: path to the archive file         path: path to extract the archive file         archive_format: Archive format to try for extracting the file.             Options are 'auto', 'tar', 'zip', and None.             'tar' includes tar, tar.gz, and tar.bz files.             The default 'auto' is ['tar', 'zip'].             None or an empty list will return no matches found.      # Returns         True if a match was found and an archive extraction was completed,         False otherwise. # check weather extracted or not #              untar=False, Downloads a file from a URL if it not already in the cache.      By default the file at the url `origin` is downloaded to the     cache_dir `/tmp/datasets`      Files in tar, tar.gz, tar.bz, and zip formats can also be extracted.     Passing a hash will verify the file after download. The command line     programs `shasum` and `sha256sum` can compute the hash.      # Arguments         origin: Original URL of the file.         fname: Name of the file. If an absolute path `/path/to/file.txt` is             specified the file will be saved at that location.             By default fname will remain it's original name.         md5_hash: Deprecated in favor of 'file_hash'.             md5 hash of the file for verification         file_hash: The expected hash string of the file after download.             The sha256 and md5 hash algorithms are both supported.         cache_dir: Location to store cached files, when None it             defaults to /tmp/datasets         cache_subdir: Subdirectory under the cache_dir where the file is             saved. If an absolute path `/path/to/folder` is             specified the file will be saved at that location.         hash_algorithm: Select the hash algorithm to verify the file.             options are 'md5', 'sha256', and 'auto'.             The default 'auto' detects the hash algorithm in use.         extract: True tries extracting the file as an Archive, like tar or zip.         archive_format: Archive format to try for extracting the file.             Options are 'auto', 'tar', 'zip', and None.             'tar' includes tar, tar.gz, and tar.bz files.             The default 'auto' is ['tar', 'zip'].             None or an empty list will return no matches found.      # Returns         Path to the downloaded file # File found; verify integrity if a hash was provided. # Maintain progbar for the lifetime of download. # This design was chosen for Python 2.7 compatibility.