Skip to content
queries.py 5.94 KiB
Newer Older
Franziska Koehn's avatar
Franziska Koehn committed
"""
:Author: Franziska Koehn
:Created: 2015/01/13

This module includes functions around sending and defining queries.
Franziska Koehn's avatar
Franziska Koehn committed

to query the xnat server define:

one string including one Root-Type like:

.. sourcecode:: python

   'xnat:mrScanData'

one list including the search-constraints like:

.. code-block:: python

    [
        ('xnat:mrScanData/TYPE', 'LIKE', '%t2%'),
        ('xnat:mrScanData/PARAMETERS_FLIP', '>=', '10'),
        'AND',
        [('xnat:mrScanData/PARAMETERS_TE', '>', '2.0'),
         ('xnat:mrScanData/PARAMETERS_TE', '<', '2.0'),
         'OR'
         ]
    ]

a list of search-fields like:

.. code-block:: python

    [ 'xnat:mrScanData/TYPE','xnat:mrScanData/ID']

Franziska Koehn's avatar
Franziska Koehn committed
"""

Franziska Koehn's avatar
Franziska Koehn committed
from threading import Lock
requests_lock = Lock()

Franziska Koehn's avatar
Franziska Koehn committed
    """Returns all applicable methods for creating a query."""
Franziska Koehn's avatar
Franziska Koehn committed
    """Returns all applicable Operators for creating a query."""
Franziska Koehn's avatar
Franziska Koehn committed

def download_async(result, host, creds, rest, dest_folder='', cb=(lambda *_: None), cb_args=()):
Franziska Koehn's avatar
Franziska Koehn committed
    """
Franziska Koehn's avatar
Franziska Koehn committed
    Downloads file by using threads (So the GUI will not be blocked while downloading).
Franziska Koehn's avatar
Franziska Koehn committed

    **Parameters**
Franziska Koehn's avatar
Franziska Koehn committed
        :result: dict, resultset from which will be downloaded
        :host: str, address of host
        :creds: tuple (username, userpassword), credentials (including user-name and -password)
        :rest: str, REST-API definition
        :dest_folder: str, folder where the downloaded files will be saved
        :cb: function, that will be called, when download is finished with the arguments from cb_args
Franziska Koehn's avatar
Franziska Koehn committed
        :cb_args: args for function cb
    """
Franziska Koehn's avatar
Franziska Koehn committed
    from threading import Thread
    download_thread = Thread(target=download, args=(result, host, creds, rest, dest_folder, cb, cb_args))
Franziska Koehn's avatar
Franziska Koehn committed
    download_thread.start()
    return download_thread
Franziska Koehn's avatar
Franziska Koehn committed

def download(result, host, creds, rest, dest_folder='', cb=(lambda *_: None), cb_args=()):
Franziska Koehn's avatar
Franziska Koehn committed
    """
Franziska Koehn's avatar
Franziska Koehn committed
    Downloads a Result.
Franziska Koehn's avatar
Franziska Koehn committed

    **Parameters**
Franziska Koehn's avatar
Franziska Koehn committed
        :result: dict, resultset from which will be downloaded
        :host: str, address of host
        :creds: tuple (username, userpassword), credentials (including user-name and -password)
        :rest: str, REST-API definition
        :dest_folder: str, folder where the downloaded files will be saved
        :cb: function, that will be called, when download is finished with the arguments from cb_args
Franziska Koehn's avatar
Franziska Koehn committed
        :cb_args: args for function cb
    """

Franziska Koehn's avatar
Franziska Koehn committed
    requests_lock.acquire()

    import re
    import os

    names=[]
    def subfunc(f):
        key = f.group(0).strip("{}")
        r = result[key]
        names.append(r)
        return r
    ret = re.sub('\{\w+\}', subfunc, rest)

    path = os.path.join(dest_folder, '-'.join(names))
    url = "%s%s" % (host, ret)

    download_file(url, creds, path)
Franziska Koehn's avatar
Franziska Koehn committed
    requests_lock.release()
    cb(*cb_args)
def download_file(url, creds, path):
Franziska Koehn's avatar
Franziska Koehn committed
    """
Franziska Koehn's avatar
Franziska Koehn committed
    Downloads a file from given 'url' and saves it to 'path'.

    Returns True if download was finished without problems
    Returns False if download raised an exception.
Franziska Koehn's avatar
Franziska Koehn committed

    **Parameters**
Franziska Koehn's avatar
Franziska Koehn committed
        :url: str, host/REST-API with filled values
        :creds: tuple(user-name, user-password), credentials
        :path: str, folder where the downloaded files will be saved
Franziska Koehn's avatar
Franziska Koehn committed
    """

    import requests
    from base64 import b64encode
    from requests.auth import HTTPBasicAuth

    if not path.endswith(".zip"):
        path += ".zip"
        with open(path, 'wb') as handle:
            response = requests.get(url, stream=True, auth=HTTPBasicAuth(user, passw))
            if not response.ok:
                raise ValueError(response.status_code)
            for block in response.iter_content(1024):
                if not block:
                    break
                handle.write(block)
Franziska Koehn's avatar
Franziska Koehn committed
        return True
    except IOError as e:
        print "Error writing file %s, %s" % (path, e)
    except ValueError as e:
        print "Error downloading file %s, Status Code %s" % (url, e)
Franziska Koehn's avatar
Franziska Koehn committed
    return False
def search_for(host, root_element, constraints, search_fields, user, passw):
Franziska Koehn's avatar
Franziska Koehn committed
    """
    Does a search for given values. raises xsa -Exceptions

    **Parameters**
Franziska Koehn's avatar
Franziska Koehn committed
        :host: str, host-address
        :root_element: str, Root-Type of search
        :constraints: list, constraints of query
        :search_fields: list of str, fields which will be returned from server
        :user: str, user-name
        :passw: str, user-password

    **Raises**
        :xsa.errors.ServerNotFoundError:
        :xsa.errors.UnauthorizedError:
        :xsa.errors.ResponseNotReady:
        :xsa.errors.QueryError:


Franziska Koehn's avatar
Franziska Koehn committed
    """
Franziska Koehn's avatar
Franziska Koehn committed
    import xsa.errors
    from pyxnat.core import errors
    from httplib2 import ServerNotFoundError
    from httplib import ResponseNotReady

    from tempfile import mkdtemp
    from pyxnat import Interface
        central = Interface(server=host,
                            user=user,
                            password=passw,
                            cachedir=tmp_dir)
    except IndexError as e:
Franziska Koehn's avatar
Franziska Koehn committed
        raise xsa.errors.ServerNotFoundError("Server not found, check your host-address.")
    result = []

    try:
        result =  central.select(root_element,search_fields).where(constraints)
    except errors.DatabaseError as e:
        if '401' in str(e):
Franziska Koehn's avatar
Franziska Koehn committed
            raise xsa.errors.UnauthorizedError("Unauthorizied attempt. Check your User and Password")
        else:
            raise e
    except ServerNotFoundError:
Franziska Koehn's avatar
Franziska Koehn committed
        raise xsa.errors.ServerNotFoundError("Server not found, check your host-address.")
    except ResponseNotReady:
Franziska Koehn's avatar
Franziska Koehn committed
        raise xsa.errors.ResponseNotReady("Please check your Host-Address")

    if result == []:
Franziska Koehn's avatar
Franziska Koehn committed
        raise xsa.errors.QueryError("Please check your query.")

    try:
        central.disonnect()
    except AttributeError:
        print "can\'t close connection (wrong pyxnat version?)"

    try:
        from shutil import rmtree
        rmtree(tmp_dir)
    except:
        pass