def download(auth, label, scan_ids=None, project=None, aid=None,
             out_dir='.', in_mem=True, progress=False, attempts=1):
    '''
    Download scan data from XNAT.
    
    Example:
        >>> import yaxil
        >>> auth = yaxil.XnatAuth(url='...', username='...', password='...')
        >>> yaxil.download(auth, 'AB1234C', ['1', '2'], out_dir='./data')

    :param auth: XNAT authentication object
    :type auth: :mod:`yaxil.XnatAuth`
    :param label: XNAT MR Session label
    :type label: str
    :param scan_ids: Scan numbers to return; use None for all
    :type scan_ids: list
    :param project: XNAT MR Session project
    :type project: str
    :param aid: XNAT Accession ID
    :type aid: str
    :param out_dir: Output directory
    :type out_dir: str
    :param in_mem: Keep download content in memory; faster but uses more memory
    :type in_mem: bool
    :param progress: Show download progress every N bytes
    :type progress: int
    :param attempts: Number of download attempts
    :type attempts: int
    ''' 
    if not scan_ids:
        scan_ids = ['ALL']
    if not aid:
        aid = accession(auth, label, project)
    # build the url
    url = "%s/data/experiments/%s/scans/%s/files?format=zip" % (auth.url.rstrip('/'), 
            aid, ','.join([str(x) for x in scan_ids]))
    # issue the http request, with exponential backoff retry behavior
    backoff = 10
    for _ in range(attempts): 
        logger.debug("issuing http request %s", url)
        r = requests.get(url, stream=True, auth=(auth.username, auth.password), verify=CHECK_CERTIFICATE)
        logger.debug("response headers %s", r.headers)
        if r.status_code == requests.codes.ok:
            break
        fuzz = random.randint(0, 10)
        logger.warn("download unsuccessful (%s), retrying in %s seconds", r.status_code, 
                    backoff + fuzz)
        time.sleep(backoff + fuzz)
        backoff *= 2
    # if we still have a not-ok status at this point, the download failed
    if r.status_code != requests.codes.ok:
        raise DownloadError("response not ok (%s) from %s" % (r.status_code, r.url))
    # create output directory
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)
    # keep response content in memory or write to a file (memory is obviously faster, but limited)
    if in_mem:
        content = io.BytesIO()
        logger.debug("response content will be read into memory")
    else:
        content = tf.NamedTemporaryFile(dir=out_dir, prefix="xnat", suffix=".zip")
        logger.debug("response content will be stored on disk %s", content.name)
    # progress indicator setup
    if progress:
        sys.stdout.write("reading response data: ")
        sys.stdout.flush()
    # read response content in chunks
    meter = 0
    chunk_size = 1024
    for chunk in r.iter_content(chunk_size=chunk_size):
        if progress and meter >= progress:
            sys.stdout.write(next(commons.spinner)); sys.stdout.flush()
            sys.stdout.write('\b')
            meter = 0
        content.write(chunk)
        meter += chunk_size
    # progress indicator shut down
    if progress:
        sys.stdout.write('done.\n'); sys.stdout.flush()
    # load reponse content into a zipfile object
    try:
        zf = zipfile.ZipFile(content, allowZip64=True)
    except zipfile.BadZipfile:
        with tf.NamedTemporaryFile(dir=out_dir, prefix="xnat",
                                   suffix=".zip", delete=False) as fo:
            content.seek(0)
            fo.write(content.read())
        raise DownloadError("bad zip file, written to %s" % fo.name)
    # finally extract the zipfile (with various nasty edge cases handled)
    logger.debug("extracting zip archive to %s", out_dir)
    extract(zf, content, out_dir)
def download ( auth , label , scan_ids = None , project = None , aid = None , out_dir = '.' , in_mem = True , progress = False , attempts = 1 ) : if not scan_ids : scan_ids = [ 'ALL' ] if not aid : aid = accession ( auth , label , project ) url = "%s/data/experiments/%s/scans/%s/files?format=zip" % ( auth . url . rstrip ( '/' ) , aid , ',' . join ( [ str ( x ) for x in scan_ids ] ) ) backoff = 10 for _ in range ( attempts ) : logger . debug ( "issuing http request %s" , url ) r = requests . get ( url , stream = True , auth = ( auth . username , auth . password ) , verify = CHECK_CERTIFICATE ) logger . debug ( "response headers %s" , r . headers ) if r . status_code == requests . codes . ok : break fuzz = random . randint ( 0 , 10 ) logger . warn ( "download unsuccessful (%s), retrying in %s seconds" , r . status_code , backoff + fuzz ) time . sleep ( backoff + fuzz ) backoff *= 2 if r . status_code != requests . codes . ok : raise DownloadError ( "response not ok (%s) from %s" % ( r . status_code , r . url ) ) if not os . path . exists ( out_dir ) : os . makedirs ( out_dir ) if in_mem : content = io . BytesIO ( ) logger . debug ( "response content will be read into memory" ) else : content = tf . NamedTemporaryFile ( dir = out_dir , prefix = "xnat" , suffix = ".zip" ) logger . debug ( "response content will be stored on disk %s" , content . name ) if progress : sys . stdout . write ( "reading response data: " ) sys . stdout . flush ( ) meter = 0 chunk_size = 1024 for chunk in r . iter_content ( chunk_size = chunk_size ) : if progress and meter >= progress : sys . stdout . write ( next ( commons . spinner ) ) ; sys . stdout . flush ( ) sys . stdout . write ( '\b' ) meter = 0 content . write ( chunk ) meter += chunk_size if progress : sys . stdout . write ( 'done.\n' ) ; sys . stdout . flush ( ) try : zf = zipfile . ZipFile ( content , allowZip64 = True ) except zipfile . BadZipfile : with tf . NamedTemporaryFile ( dir = out_dir , prefix = "xnat" , suffix = ".zip" , delete = False ) as fo : content . seek ( 0 ) fo . write ( content . read ( ) ) raise DownloadError ( "bad zip file, written to %s" % fo . name ) logger . debug ( "extracting zip archive to %s" , out_dir ) extract ( zf , content , out_dir )
Download scan data from XNAT.
    
    Example:
        >>> import yaxil
        >>> auth = yaxil.XnatAuth(url='...', username='...', password='...')
        >>> yaxil.download(auth, 'AB1234C', ['1', '2'], out_dir='./data')

    :param auth: XNAT authentication object
    :type auth: :mod:`yaxil.XnatAuth`
    :param label: XNAT MR Session label
    :type label: str
    :param scan_ids: Scan numbers to return; use None for all
    :type scan_ids: list
    :param project: XNAT MR Session project
    :type project: str
    :param aid: XNAT Accession ID
    :type aid: str
    :param out_dir: Output directory
    :type out_dir: str
    :param in_mem: Keep download content in memory; faster but uses more memory
    :type in_mem: bool
    :param progress: Show download progress every N bytes
    :type progress: int
    :param attempts: Number of download attempts
    :type attempts: int