xnat_search.py 6.73 KB
Newer Older
1
HOST = None
2

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

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
def main(host):
    import distutils.core

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



    results = search_for(host, root_element, constraints)

    print "Search results (%s):" % len(results)
    print results

    while True:
        try:
            is_downl = distutils.util.strtobool(raw_input("download? "))
            break
        except ValueError:
            print "invalid character. Please use y or n."

    if is_downl:
        print "downloading files..."
        download_all(results, host)
        print "finished"
    else:
        print "download canceled"

41
42
43
44
45
46
47
48
49
50
def read_json_from_file():
    pass

def get_data_types():
    from os import listdir
    from os.path import isfile, join
    import json

    DIR = 'datatypes/'
    files = [ f for f in listdir(DIR) if isfile(join(DIR,f)) ]
51
    result = []
52
53
54
    for file in files:
        with open(join(DIR,file)) as f:
            try:
55
56
                data=json.loads(f.read())['root-type']
                result.append(data)
57
            except ValueError:
58
59
60
61
62
63
64
65
66
67
                pass
    return result

def get_field_labels_of_type(type):
    result = []
    fields = get_fields_of_type(type)
    if fields is not None:
        for f in fields:
            result.append(f['label'])
    return result
68

69
70
71
72
73
74
75
76
def get_field_labels_required_of_type(type):
    result = []
    fields = get_fields_of_type(type)
    if fields is not None:
        for f in fields:
            result.append((f['label'],f['required']))
    return result

77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def get_fields_of_type(type):
    from os import listdir
    from os.path import isfile, join
    import json

    DIR = 'datatypes/'
    files = [ f for f in listdir(DIR) if isfile(join(DIR,f)) ]
    for file in files:
        with open(join(DIR,file)) as f:
            try:
                t = json.loads(f.read())
                if t['root-type'] == type:
                    return t['fields']
            except ValueError:
                pass

93
94
95
96
97
98
99
def get_field_label(type, key):
    fields = get_fields_of_type(type)
    for f in fields:
        if "key" in f and f["key"] == key:
            return f["label"]
    return key

Franziska Koehn's avatar
Franziska Koehn committed
100
101
102
103
104
105
106
107
108
109
110
def get_fields_from_labels(labels, type):
    result=[]
    fields = get_fields_of_type(type)
    if fields is not None:
        for l in labels:
            for f in fields:
                if f['label'] == l:
                    result.append(f['field'])
                    break
    return result

111
112
113
114
115
116
def get_query_methods():
    return ["AND", "OR"]

def get_operators():
    return ["LIKE", ">", "<", "<=", ">=", "="]

117
def download_all(results, host=None):
118
    for r in results:
119
120
        download(r, host)

121
def download_async(result, dest_folder='', host=None, cb=(lambda *_: None), cb_args=()):
Franziska Koehn's avatar
Franziska Koehn committed
122
    from threading import Thread
123
    download_thread = Thread(target=download, args=(result, dest_folder, host, cb, cb_args))
Franziska Koehn's avatar
Franziska Koehn committed
124
125
    download_thread.start()
    return download_thread
Franziska Koehn's avatar
Franziska Koehn committed
126

127
def download(result, dest_folder='', host=None, cb=(lambda *_: None), cb_args=()):
128
129
    if not host:
        host = HOST
Franziska Koehn's avatar
Franziska Koehn committed
130
    requests_lock.acquire()
131
132
133
134
135
    print(result)
    subject = result['xnat_mrsessiondata_subject_id']
    experiment = result['xnat_mrsessiondata_session_id']
    project = result['xnat_mrsessiondata_project']
    scan = result['id']
136
    file_name = "%s/%s-%s-%s-%s" % (dest_folder, project, subject, experiment, scan)
137
    download_file(host, project, subject, experiment, scan, file_name)
Franziska Koehn's avatar
Franziska Koehn committed
138
139
    requests_lock.release()
    cb(*cb_args)
140

141
def search_for(host, root_element, constraints, search_fields, user, passw):
142
    from pyxnat import Interface
143
    from pyxnat.core import errors
144
    from tempfile import mkdtemp
145
    from httplib2 import ServerNotFoundError
146

147
148
    get_credentials(username=user, password=passw, force=True)

149
150
    user, passw = get_credentials()
    tmp_dir=mkdtemp()
151
152
153
154
155
156
157
158

    try:
        central = Interface(server="%s" % host,
                  user=user,
                  password=passw,
                  cachedir=tmp_dir)
    except IndexError:
        return "ServerNotFoundError"    #TODO Eigene Fehlerklasse
159

160
161
162
163
164
165
166
167
    result = []

    try:
        result =  central.select(root_element,search_fields).where(constraints)
    except errors.DatabaseError:
        return "DatabaseError"   #TODO Eigene Fehlerklasse
    except ServerNotFoundError:
        return "ServerNotFoundError"    #TODO Eigene Fehlerklasse
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235

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

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


def get_credentials(force=False,username="", password="" ):
    if get_credentials.cache and not force:
        return get_credentials.cache
    from getpass import getpass
    while not len(username):
        username = raw_input("Username: ").strip()
    while not len(password):
        password = getpass().strip()
    get_credentials.cache = username, password
    return get_credentials()
get_credentials.cache = None

def download_file(host, project, subject, experiment, scan, file_name):
    import requests
    from base64 import b64encode
    from requests.auth import HTTPBasicAuth

    if not file_name.endswith(".zip"):
        file_name += ".zip"

    url= "%s/data/archive/projects/%s/subjects/%s/experiments/%s/scans/%s/resources/DICOM/files?format=zip" % (host, project, subject, experiment, scan)

    user, passw = get_credentials()

    try:
        with open(file_name, '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)
    except IOError as e:
        print "Error writing file %s, %s" % (file_name, e)
    except ValueError as e:
        print "Error downloading file %s, Status Code %s" % (url, e)

if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description='search and download')
    parser.add_argument('--host', type=str, help='hostname or ip-address (including port).', default="localhost:8080")
    parser.add_argument('--user', type=str, help='user:passw', default=":")

    #TODO force download (boolean)
    #TODO read constraints und root_element from file
    #TODO GUI

    args = parser.parse_args()

    u,p = args.user.split(':')
    get_credentials(username=u, password=p)
    main(args.host)