Mercurial > hg > orthanc-tests
annotate Tests/Toolbox.py @ 21:2a29bcff60a7
tests of image decoding
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 22 Jun 2015 14:14:37 +0200 |
parents | 7b69a561f4d3 |
children | 156c7ae164b5 |
rev | line source |
---|---|
0 | 1 #!/usr/bin/python |
2 | |
1 | 3 # Orthanc - A Lightweight, RESTful DICOM Store |
4 # Copyright (C) 2012-2015 Sebastien Jodogne, Medical Physics | |
5 # Department, University Hospital of Liege, Belgium | |
6 # | |
7 # This program is free software: you can redistribute it and/or | |
8 # modify it under the terms of the GNU General Public License as | |
9 # published by the Free Software Foundation, either version 3 of the | |
10 # License, or (at your option) any later version. | |
11 # | |
12 # This program is distributed in the hope that it will be useful, but | |
13 # WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 # General Public License for more details. | |
16 # | |
17 # You should have received a copy of the GNU General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
0 | 19 |
20 | |
21 import hashlib | |
22 import httplib2 | |
23 import json | |
4 | 24 import os |
1 | 25 import re |
4 | 26 import signal |
1 | 27 import subprocess |
4 | 28 import threading |
0 | 29 import time |
1 | 30 import zipfile |
0 | 31 |
3 | 32 from PIL import Image |
33 from urllib import urlencode | |
34 | |
0 | 35 |
36 # http://stackoverflow.com/a/1313868/881731 | |
37 try: | |
38 from cStringIO import StringIO | |
39 except: | |
40 from StringIO import StringIO | |
41 | |
42 | |
13 | 43 def DefineOrthanc(server = 'localhost', |
44 restPort = 8042, | |
1 | 45 username = None, |
46 password = None, | |
47 aet = 'ORTHANC', | |
48 dicomPort = 4242): | |
13 | 49 #m = re.match(r'(http|https)://([^:]+):([^@]+)@([^@]+)', url) |
50 #if m != None: | |
51 # url = m.groups()[0] + '://' + m.groups()[3] | |
52 # username = m.groups()[1] | |
53 # password = m.groups()[2] | |
0 | 54 |
13 | 55 #if not url.endswith('/'): |
56 # url += '/' | |
0 | 57 |
1 | 58 return { |
13 | 59 'Server' : server, |
60 'Url' : 'http://%s:%d/' % (server, restPort), | |
1 | 61 'Username' : username, |
62 'Password' : password, | |
63 'DicomAet' : aet, | |
64 'DicomPort' : dicomPort | |
65 } | |
0 | 66 |
67 | |
68 def _SetupCredentials(orthanc, http): | |
1 | 69 if (orthanc['Username'] != None and |
70 orthanc['Password'] != None): | |
71 http.add_credentials(orthanc['Username'], orthanc['Password']) | |
0 | 72 |
73 | |
74 def DoGet(orthanc, uri, data = {}, body = None, headers = {}): | |
75 d = '' | |
76 if len(data.keys()) > 0: | |
77 d = '?' + urlencode(data) | |
78 | |
79 http = httplib2.Http() | |
21
2a29bcff60a7
tests of image decoding
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
80 http.follow_redirects = False |
0 | 81 _SetupCredentials(orthanc, http) |
82 | |
1 | 83 resp, content = http.request(orthanc['Url'] + uri + d, 'GET', body = body, |
0 | 84 headers = headers) |
85 if not (resp.status in [ 200 ]): | |
86 raise Exception(resp.status) | |
87 else: | |
88 try: | |
89 return json.loads(content) | |
90 except: | |
91 return content | |
92 | |
93 def _DoPutOrPost(orthanc, uri, method, data, contentType, headers): | |
94 http = httplib2.Http() | |
21
2a29bcff60a7
tests of image decoding
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
95 http.follow_redirects = False |
0 | 96 _SetupCredentials(orthanc, http) |
97 | |
98 if isinstance(data, str): | |
99 body = data | |
100 if len(contentType) != 0: | |
101 headers['content-type'] = contentType | |
102 else: | |
103 body = json.dumps(data) | |
104 headers['content-type'] = 'application/json' | |
105 | |
106 headers['expect'] = '' | |
107 | |
1 | 108 resp, content = http.request(orthanc['Url'] + uri, method, |
0 | 109 body = body, |
110 headers = headers) | |
111 if not (resp.status in [ 200, 302 ]): | |
112 raise Exception(resp.status) | |
113 else: | |
114 try: | |
115 return json.loads(content) | |
116 except: | |
117 return content | |
118 | |
119 def DoDelete(orthanc, uri): | |
120 http = httplib2.Http() | |
21
2a29bcff60a7
tests of image decoding
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
13
diff
changeset
|
121 http.follow_redirects = False |
0 | 122 _SetupCredentials(orthanc, http) |
123 | |
1 | 124 resp, content = http.request(orthanc['Url'] + uri, 'DELETE') |
0 | 125 if not (resp.status in [ 200 ]): |
126 raise Exception(resp.status) | |
127 else: | |
128 try: | |
129 return json.loads(content) | |
130 except: | |
131 return content | |
132 | |
133 def DoPut(orthanc, uri, data = {}, contentType = ''): | |
10 | 134 return _DoPutOrPost(orthanc, uri, 'PUT', data, contentType, {}) |
0 | 135 |
136 def DoPost(orthanc, uri, data = {}, contentType = '', headers = {}): | |
137 return _DoPutOrPost(orthanc, uri, 'POST', data, contentType, headers) | |
138 | |
13 | 139 def GetDatabasePath(filename): |
140 return os.path.join(os.path.dirname(__file__), '..', 'Database', filename) | |
141 | |
0 | 142 def UploadInstance(orthanc, filename): |
13 | 143 f = open(GetDatabasePath(filename), 'rb') |
0 | 144 d = f.read() |
145 f.close() | |
146 return DoPost(orthanc, '/instances', d, 'application/dicom') | |
147 | |
148 def UploadFolder(orthanc, path): | |
13 | 149 for i in os.listdir(GetDatabasePath(path)): |
1 | 150 try: |
151 UploadInstance(orthanc, os.path.join(path, i)) | |
152 except: | |
153 pass | |
0 | 154 |
155 def DropOrthanc(orthanc): | |
156 # Reset the Lua callbacks | |
157 DoPost(orthanc, '/tools/execute-script', 'function OnStoredInstance(instanceId, tags, metadata) end', 'application/lua') | |
158 | |
159 DoDelete(orthanc, '/exports') | |
160 | |
161 for s in DoGet(orthanc, '/patients'): | |
162 DoDelete(orthanc, '/patients/%s' % s) | |
163 | |
164 def ComputeMD5(data): | |
165 m = hashlib.md5() | |
166 m.update(data) | |
167 return m.hexdigest() | |
168 | |
169 def GetImage(orthanc, uri): | |
170 # http://www.pythonware.com/library/pil/handbook/introduction.htm | |
171 data = DoGet(orthanc, uri) | |
172 return Image.open(StringIO(data)) | |
173 | |
174 def GetArchive(orthanc, uri): | |
175 # http://stackoverflow.com/a/1313868/881731 | |
176 s = DoGet(orthanc, uri) | |
177 return zipfile.ZipFile(StringIO(s), "r") | |
178 | |
1 | 179 def IsDefinedInLua(orthanc, name): |
0 | 180 s = DoPost(orthanc, '/tools/execute-script', 'print(type(%s))' % name, 'application/lua') |
181 return (s.strip() != 'nil') | |
182 | |
1 | 183 def WaitEmpty(orthanc): |
0 | 184 while True: |
1 | 185 if len(DoGet(orthanc, '/instances')) == 0: |
0 | 186 return |
187 time.sleep(0.1) | |
188 | |
1 | 189 def GetDockerHostAddress(): |
190 route = subprocess.check_output([ '/sbin/ip', 'route' ]) | |
191 m = re.search(r'default via ([0-9.]+)', route) | |
192 if m == None: | |
193 return 'localhost' | |
194 else: | |
195 return m.groups()[0] | |
4 | 196 |
197 | |
198 | |
199 | |
200 class ExternalCommandThread: | |
201 @staticmethod | |
202 def ExternalCommandFunction(arg, stop_event, command, env): | |
203 external = subprocess.Popen(command, env = env) | |
204 | |
205 while (not stop_event.is_set()): | |
206 error = external.poll() | |
207 if error != None: | |
208 # http://stackoverflow.com/a/1489838/881731 | |
209 os._exit(-1) | |
210 stop_event.wait(0.1) | |
211 | |
212 print 'Stopping the external command' | |
213 external.terminate() | |
9 | 214 external.communicate() # Wait for the command to stop |
4 | 215 |
216 def __init__(self, command, env = None): | |
217 self.thread_stop = threading.Event() | |
218 self.thread = threading.Thread(target = self.ExternalCommandFunction, | |
219 args = (10, self.thread_stop, command, env)) | |
9 | 220 #self.daemon = True |
4 | 221 self.thread.start() |
222 | |
223 def stop(self): | |
224 self.thread_stop.set() | |
225 self.thread.join() |