def download(url, fpath=None, hash_prefix=None, hasher='<STR_LIT>',<EOL>chunksize=<NUM_LIT>, verbose=<NUM_LIT:1>):
from progiter import ProgIter as Progress<EOL>from ubelt import util_platform<EOL>import shutil<EOL>import tempfile<EOL>import hashlib<EOL>if six.PY2:  <EOL><INDENT>from urllib2 import urlopen  <EOL><DEDENT>else:<EOL><INDENT>from urllib.request import urlopen  <EOL><DEDENT>if fpath is None:<EOL><INDENT>dpath = util_platform.ensure_app_cache_dir('<STR_LIT>')<EOL>fname = basename(url)<EOL>fpath = join(dpath, fname)<EOL><DEDENT>_dst_is_io_object = hasattr(fpath, '<STR_LIT>')<EOL>if verbose:<EOL><INDENT>if _dst_is_io_object:<EOL><INDENT>print('<STR_LIT>' % (url,))<EOL><DEDENT>else:<EOL><INDENT>print('<STR_LIT>' % (url, fpath))<EOL><DEDENT><DEDENT>urldata = urlopen(url)<EOL>meta = urldata.info()<EOL>try:<EOL><INDENT>if hasattr(meta, '<STR_LIT>'):  <EOL><INDENT>file_size = int(meta.getheaders("<STR_LIT>")[<NUM_LIT:0>])<EOL><DEDENT>else:<EOL><INDENT>file_size = int(meta.get_all("<STR_LIT>")[<NUM_LIT:0>])<EOL><DEDENT><DEDENT>except Exception:  <EOL><INDENT>file_size = None<EOL><DEDENT>if hash_prefix:<EOL><INDENT>if isinstance(hasher, six.string_types):<EOL><INDENT>if hasher == '<STR_LIT>':<EOL><INDENT>hasher = hashlib.sha1()<EOL><DEDENT>elif hasher == '<STR_LIT>':<EOL><INDENT>hasher = hashlib.sha512()<EOL><DEDENT>else:<EOL><INDENT>raise KeyError(hasher)<EOL><DEDENT><DEDENT><DEDENT>if _dst_is_io_object:<EOL><INDENT>_file_write = fpath.write<EOL><DEDENT>else:<EOL><INDENT>tmp = tempfile.NamedTemporaryFile(delete=False)<EOL>_file_write = tmp.write<EOL><DEDENT>_urldata_read = urldata.read<EOL>try:<EOL><INDENT>with Progress(total=file_size, disable=not verbose) as pbar:<EOL><INDENT>_pbar_update = pbar.update<EOL>def _critical_loop():<EOL><INDENT>buffer = '<STR_LIT:U+0020>'<EOL>if hash_prefix:<EOL><INDENT>_hasher_update = hasher.update<EOL>while buffer:<EOL><INDENT>buffer = _urldata_read(chunksize)<EOL>_file_write(buffer)<EOL>_hasher_update(buffer)<EOL>_pbar_update(len(buffer))<EOL><DEDENT><DEDENT>else:<EOL><INDENT>while buffer:<EOL><INDENT>buffer = _urldata_read(chunksize)<EOL>_file_write(buffer)<EOL>_pbar_update(len(buffer))<EOL><DEDENT><DEDENT><DEDENT>_critical_loop()<EOL><DEDENT>if not _dst_is_io_object:<EOL><INDENT>tmp.close()<EOL>shutil.move(tmp.name, fpath)<EOL><DEDENT>if hash_prefix:<EOL><INDENT>got = hasher.hexdigest()<EOL>if got[:len(hash_prefix)] != hash_prefix:<EOL><INDENT>print('<STR_LIT>'.format(hash_prefix))<EOL>print('<STR_LIT>'.format(got))<EOL>if _dst_is_io_object:<EOL><INDENT>raise RuntimeError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(hash_prefix, got))<EOL><DEDENT>else:<EOL><INDENT>raise RuntimeError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'.format(<EOL>fpath, hash_prefix, got))<EOL><DEDENT><DEDENT><DEDENT><DEDENT>finally:<EOL><INDENT>if not _dst_is_io_object:  <EOL><INDENT>tmp.close()<EOL>if exists(tmp.name):<EOL><INDENT>os.remove(tmp.name)<EOL><DEDENT><DEDENT><DEDENT>return fpath<EOL>
downloads a url to a fpath.

Args:
    url (str):
        The url to download.

    fpath (PathLike | io.BytesIOtringIO):
        The path to download to. Defaults to basename of url and ubelt's
        application cache. If this is a io.BytesIO object then information
        is directly written to this object (note this prevents the use of
        temporary files).

    hash_prefix (None or str):
        If specified, download will retry / error if the file hash
        does not match this value. Defaults to None.

    hasher (str or Hasher):
        If hash_prefix is specified, this indicates the hashing
        algorithm to apply to the file. Defaults to sha512.

    chunksize (int):
        Download chunksize. Defaults to 2 ** 13.

    verbose (int):
        Verbosity level 0 or 1. Defaults to 1.

Returns:
    PathLike: fpath - file path string

Raises:
    URLError - if there is problem downloading the url
    RuntimeError - if the hash does not match the hash_prefix

Notes:
    Original code taken from pytorch in torch/utils/model_zoo.py and
    slightly modified.

References:
    http://blog.moleculea.com/2012/10/04/urlretrieve-progres-indicator/
    http://stackoverflow.com/questions/15644964/python-progress-bar-and-downloads
    http://stackoverflow.com/questions/16694907/how-to-download-large-file-in-python-with-requests-py

CommandLine:
    python -m xdoctest ubelt.util_download download:1

Example:
    >>> # xdoctest: +REQUIRES(--network)
    >>> from ubelt.util_download import *  # NOQA
    >>> url = 'http://i.imgur.com/rqwaDag.png'
    >>> fpath = download(url)
    >>> print(basename(fpath))
    rqwaDag.png

Example:
    >>> # xdoctest: +REQUIRES(--network)
    >>> import ubelt as ub
    >>> import io
    >>> url = 'http://i.imgur.com/rqwaDag.png'
    >>> file = io.BytesIO()
    >>> fpath = download(url, file)
    >>> file.seek(0)
    >>> data = file.read()
    >>> assert ub.hash_data(data, hasher='sha1').startswith('f79ea24571')

Example:
    >>> # xdoctest: +REQUIRES(--network)
    >>> url = 'http://i.imgur.com/rqwaDag.png'
    >>> fpath = download(url, hasher='sha1', hash_prefix='f79ea24571da6ddd2ba12e3d57b515249ecb8a35')
    Downloading url='http://i.imgur.com/rqwaDag.png' to fpath=...rqwaDag.png
    ...
    ...1233/1233... rate=... Hz, eta=..., total=..., wall=...

Example:
    >>> # xdoctest: +REQUIRES(--network)
    >>> # test download from girder
    >>> import pytest
    >>> import ubelt as ub
    >>> url = 'https://data.kitware.com/api/v1/item/5b4039308d777f2e6225994c/download'
    >>> ub.download(url, hasher='sha512', hash_prefix='c98a46cb31205cf')
    >>> with pytest.raises(RuntimeError):
    >>>     ub.download(url, hasher='sha512', hash_prefix='BAD_HASH')