qmenta-client 1.1.dev1217__py3-none-any.whl → 1.1.dev1230__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qmenta/client/Project.py +96 -47
- {qmenta_client-1.1.dev1217.dist-info → qmenta_client-1.1.dev1230.dist-info}/METADATA +1 -1
- {qmenta_client-1.1.dev1217.dist-info → qmenta_client-1.1.dev1230.dist-info}/RECORD +4 -4
- {qmenta_client-1.1.dev1217.dist-info → qmenta_client-1.1.dev1230.dist-info}/WHEEL +1 -1
qmenta/client/Project.py
CHANGED
|
@@ -23,7 +23,7 @@ logger_name = "qmenta.client"
|
|
|
23
23
|
def show_progress(done, total, finish=False):
|
|
24
24
|
bytes_in_mb = 1024 * 1024
|
|
25
25
|
progress_message = "\r[{:.2f} %] Uploaded {:.2f} of {:.2f} Mb".format(
|
|
26
|
-
done / float(total) * 100, done /
|
|
26
|
+
done / float(total) * 100, done / bytes_in_mb, total / bytes_in_mb)
|
|
27
27
|
sys.stdout.write(progress_message)
|
|
28
28
|
sys.stdout.flush()
|
|
29
29
|
if not finish:
|
|
@@ -91,15 +91,16 @@ class Project:
|
|
|
91
91
|
"""
|
|
92
92
|
|
|
93
93
|
def __init__(self, account: Account, project_id, max_upload_retries=5):
|
|
94
|
-
|
|
95
94
|
# if project_id is a string (the name of the project), get the
|
|
96
95
|
# project id (int)
|
|
97
|
-
if
|
|
96
|
+
if isinstance(project_id, str):
|
|
98
97
|
project_name = project_id
|
|
99
98
|
project_id = next(iter(filter(
|
|
100
99
|
lambda proj: proj["name"] == project_id, account.projects)
|
|
101
100
|
))["id"]
|
|
102
101
|
else:
|
|
102
|
+
if isinstance(project_id, float):
|
|
103
|
+
project_id = int(project_id)
|
|
103
104
|
project_name = next(iter(filter(
|
|
104
105
|
lambda proj: proj["id"] == project_id, account.projects)
|
|
105
106
|
))["name"]
|
|
@@ -162,9 +163,21 @@ class Project:
|
|
|
162
163
|
"""
|
|
163
164
|
return self.get_subjects_metadata(cache=False)
|
|
164
165
|
|
|
165
|
-
def get_subjects_metadata(self, cache=True):
|
|
166
|
+
def get_subjects_metadata(self, cache=True, search_criteria=None):
|
|
166
167
|
"""
|
|
167
168
|
List all subject data from the selected project.
|
|
169
|
+
Parameters
|
|
170
|
+
----------
|
|
171
|
+
cache: bool
|
|
172
|
+
Whether to use the cached metadata or not
|
|
173
|
+
|
|
174
|
+
search_criteria: dict
|
|
175
|
+
Each element is a string and is built using the formatting
|
|
176
|
+
"type;value", or "type;operation|value"
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
search_criteria = {"pars_patient_secret_name": "string;abide",
|
|
180
|
+
"pars_ssid": "integer;eq|2"}
|
|
168
181
|
|
|
169
182
|
Returns
|
|
170
183
|
-------
|
|
@@ -175,6 +188,7 @@ class Project:
|
|
|
175
188
|
if not cache or not self._subjects_metadata:
|
|
176
189
|
content = platform.parse_response(platform.post(
|
|
177
190
|
self._account.auth, "patient_manager/get_patient_list",
|
|
191
|
+
data=search_criteria,
|
|
178
192
|
headers={"X-Range": "items=0-9999"}
|
|
179
193
|
))
|
|
180
194
|
self._subjects_metadata = content
|
|
@@ -218,7 +232,7 @@ class Project:
|
|
|
218
232
|
List all the parameters in the subject metadata.
|
|
219
233
|
|
|
220
234
|
Each project has a set of parameters that define the subjects metadata.
|
|
221
|
-
This function returns all
|
|
235
|
+
This function returns all these parameters and its properties.
|
|
222
236
|
|
|
223
237
|
Returns
|
|
224
238
|
-------
|
|
@@ -284,7 +298,7 @@ class Project:
|
|
|
284
298
|
answer = {}
|
|
285
299
|
|
|
286
300
|
if title not in answer:
|
|
287
|
-
logger.error("Could not add new parameter: {}"
|
|
301
|
+
logger.error(f"Could not add new parameter: {title}")
|
|
288
302
|
return False
|
|
289
303
|
|
|
290
304
|
logger.info("New parameter added:", title, param_properties)
|
|
@@ -296,9 +310,8 @@ class Project:
|
|
|
296
310
|
elif isinstance(analysis_name_or_id, str):
|
|
297
311
|
search_tag = "p_n"
|
|
298
312
|
else:
|
|
299
|
-
raise Exception(
|
|
300
|
-
|
|
301
|
-
)
|
|
313
|
+
raise Exception("The analysis identifier must be its name or an "
|
|
314
|
+
"integer")
|
|
302
315
|
|
|
303
316
|
search_condition = {
|
|
304
317
|
search_tag: analysis_name_or_id,
|
|
@@ -309,10 +322,8 @@ class Project:
|
|
|
309
322
|
))
|
|
310
323
|
|
|
311
324
|
if len(response) > 1:
|
|
312
|
-
raise Exception(
|
|
313
|
-
|
|
314
|
-
analysis_name_or_id)
|
|
315
|
-
)
|
|
325
|
+
raise Exception(f"multiple analyses with name "
|
|
326
|
+
f"{analysis_name_or_id} found")
|
|
316
327
|
elif len(response) == 1:
|
|
317
328
|
return response[0]
|
|
318
329
|
else:
|
|
@@ -348,9 +359,8 @@ class Project:
|
|
|
348
359
|
)
|
|
349
360
|
|
|
350
361
|
if len(response) > 1:
|
|
351
|
-
raise Exception(
|
|
352
|
-
|
|
353
|
-
subject_name))
|
|
362
|
+
raise Exception(f"multiple containers for subject {subject_name} "
|
|
363
|
+
f"found")
|
|
354
364
|
elif len(response) == 1:
|
|
355
365
|
return response[0]
|
|
356
366
|
else:
|
|
@@ -500,10 +510,10 @@ class Project:
|
|
|
500
510
|
filename : str
|
|
501
511
|
Name of the file to be edited.
|
|
502
512
|
modality : str or None
|
|
503
|
-
Modality identifier, or None if the file shouldn
|
|
513
|
+
Modality identifier, or None if the file shouldn't have
|
|
504
514
|
any modality
|
|
505
515
|
tags : list[str] or None
|
|
506
|
-
List of tags, or None if the filename shouldn
|
|
516
|
+
List of tags, or None if the filename shouldn't have any tags
|
|
507
517
|
"""
|
|
508
518
|
|
|
509
519
|
tags_str = "" if tags is None else ";".join(tags)
|
|
@@ -580,15 +590,14 @@ class Project:
|
|
|
580
590
|
Name of the zip where the downloaded files are stored.
|
|
581
591
|
"""
|
|
582
592
|
logger = logging.getLogger(logger_name)
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
files_not_in_container = list(files_not_in_container)
|
|
593
|
+
files_not_in_container = list(
|
|
594
|
+
filter(lambda f: f not in self.list_container_files(container_id),
|
|
595
|
+
filenames)
|
|
596
|
+
)
|
|
588
597
|
|
|
589
598
|
if files_not_in_container:
|
|
590
|
-
msg = "The following files are missing in container
|
|
591
|
-
|
|
599
|
+
msg = (f"The following files are missing in container "
|
|
600
|
+
f"{container_id}: {', '.join(files_not_in_container)}")
|
|
592
601
|
logger.error(msg)
|
|
593
602
|
return False
|
|
594
603
|
|
|
@@ -642,6 +651,8 @@ class Project:
|
|
|
642
651
|
----------
|
|
643
652
|
subject_name : str
|
|
644
653
|
Name of the subject.
|
|
654
|
+
cache: bool
|
|
655
|
+
Whether to use the cached metadata or not
|
|
645
656
|
|
|
646
657
|
Returns
|
|
647
658
|
-------
|
|
@@ -674,9 +685,8 @@ class Project:
|
|
|
674
685
|
"""
|
|
675
686
|
logger = logging.getLogger(logger_name)
|
|
676
687
|
if self.check_subject_name(subject.name):
|
|
677
|
-
logger.error(
|
|
678
|
-
|
|
679
|
-
subject.name))
|
|
688
|
+
logger.error(f"Subject with name {subject.name} already exists in "
|
|
689
|
+
f"project!")
|
|
680
690
|
return False
|
|
681
691
|
|
|
682
692
|
try:
|
|
@@ -685,8 +695,7 @@ class Project:
|
|
|
685
695
|
data={"secret_name": subject.name}
|
|
686
696
|
))
|
|
687
697
|
except errors.PlatformError:
|
|
688
|
-
logger.error(
|
|
689
|
-
"Subject {} could not be created.".format(subject.name))
|
|
698
|
+
logger.error(f"Subject {subject.name} could not be created.")
|
|
690
699
|
return False
|
|
691
700
|
|
|
692
701
|
subject.subject_id = self.get_subject_id(subject.name)
|
|
@@ -764,7 +773,7 @@ class Project:
|
|
|
764
773
|
|
|
765
774
|
Parameters
|
|
766
775
|
----------
|
|
767
|
-
|
|
776
|
+
subject_name : str
|
|
768
777
|
Name of the subject to be deleted.
|
|
769
778
|
|
|
770
779
|
Returns
|
|
@@ -828,12 +837,12 @@ class Project:
|
|
|
828
837
|
the uploaded file into multiple sessions.
|
|
829
838
|
"""
|
|
830
839
|
|
|
831
|
-
request_headers = {
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
840
|
+
request_headers = {
|
|
841
|
+
"Content-Type": "application/zip", "Content-Range":
|
|
842
|
+
range_str, "Session-ID": str(session_id),
|
|
843
|
+
"Content-Length": str(length),
|
|
844
|
+
"Content-Disposition": disposition
|
|
845
|
+
}
|
|
837
846
|
|
|
838
847
|
if last_chunk:
|
|
839
848
|
request_headers["X-Mint-Name"] = name
|
|
@@ -885,7 +894,7 @@ class Project:
|
|
|
885
894
|
Subject to which this file will belong
|
|
886
895
|
ssid : str
|
|
887
896
|
The ID of the timepoint
|
|
888
|
-
|
|
897
|
+
date_of_scan : str
|
|
889
898
|
Date of scan/creation of the file
|
|
890
899
|
description : str
|
|
891
900
|
Description of the file
|
|
@@ -932,7 +941,6 @@ class Project:
|
|
|
932
941
|
session_id = get_session_id(file_path)
|
|
933
942
|
chunk_num = 0
|
|
934
943
|
retries_count = 0
|
|
935
|
-
error_message = ""
|
|
936
944
|
uploaded_bytes = 0
|
|
937
945
|
response = None
|
|
938
946
|
last_chunk = False
|
|
@@ -959,7 +967,7 @@ class Project:
|
|
|
959
967
|
bytes_range = "bytes " + str(start_position) + "-" + \
|
|
960
968
|
str(end_position) + "/" + str(total_bytes)
|
|
961
969
|
|
|
962
|
-
dispstr = "attachment; filename
|
|
970
|
+
dispstr = f"attachment; filename={filename}"
|
|
963
971
|
response = self._upload_chunk(
|
|
964
972
|
data, bytes_range, bytes_to_send, session_id, dispstr,
|
|
965
973
|
last_chunk,
|
|
@@ -972,6 +980,7 @@ class Project:
|
|
|
972
980
|
time.sleep(retries_count * 5)
|
|
973
981
|
if retries_count > max_retries:
|
|
974
982
|
error_message = "HTTP Connection Problem"
|
|
983
|
+
logger.error(error_message)
|
|
975
984
|
break
|
|
976
985
|
elif int(response.status_code) == 201:
|
|
977
986
|
chunk_num += 1
|
|
@@ -987,6 +996,7 @@ class Project:
|
|
|
987
996
|
error_message = (
|
|
988
997
|
"Error Code: 416; "
|
|
989
998
|
"Requested Range Not Satisfiable (NGINX)")
|
|
999
|
+
logger.error(error_message)
|
|
990
1000
|
break
|
|
991
1001
|
else:
|
|
992
1002
|
retries_count += 1
|
|
@@ -1019,6 +1029,7 @@ class Project:
|
|
|
1019
1029
|
----------
|
|
1020
1030
|
file_path : str
|
|
1021
1031
|
Path to the file to upload
|
|
1032
|
+
subject_name: str
|
|
1022
1033
|
|
|
1023
1034
|
Returns
|
|
1024
1035
|
-------
|
|
@@ -1037,6 +1048,7 @@ class Project:
|
|
|
1037
1048
|
----------
|
|
1038
1049
|
file_path : str
|
|
1039
1050
|
Path to the file to upload
|
|
1051
|
+
subject_name: str
|
|
1040
1052
|
|
|
1041
1053
|
Returns
|
|
1042
1054
|
-------
|
|
@@ -1058,6 +1070,7 @@ class Project:
|
|
|
1058
1070
|
----------
|
|
1059
1071
|
file_path : str
|
|
1060
1072
|
Path to the file to upload
|
|
1073
|
+
subject_name: str
|
|
1061
1074
|
|
|
1062
1075
|
Returns
|
|
1063
1076
|
-------
|
|
@@ -1078,7 +1091,7 @@ class Project:
|
|
|
1078
1091
|
container_id : int
|
|
1079
1092
|
ID of the container to copy.
|
|
1080
1093
|
project_id : int or str
|
|
1081
|
-
ID of the project to
|
|
1094
|
+
ID of the project to retrieve, either the numeric ID or the name
|
|
1082
1095
|
|
|
1083
1096
|
Returns
|
|
1084
1097
|
-------
|
|
@@ -1094,7 +1107,7 @@ class Project:
|
|
|
1094
1107
|
if proj["name"] == project_id]
|
|
1095
1108
|
if not projects_match:
|
|
1096
1109
|
raise Exception(
|
|
1097
|
-
"Project {}"
|
|
1110
|
+
f"Project {project_id}" +
|
|
1098
1111
|
" does not exist or is not available for this user."
|
|
1099
1112
|
)
|
|
1100
1113
|
p_id = int(projects_match[0]["id"])
|
|
@@ -1203,7 +1216,7 @@ class Project:
|
|
|
1203
1216
|
if preferred_destination:
|
|
1204
1217
|
post_data["preferred_destination"] = preferred_destination
|
|
1205
1218
|
|
|
1206
|
-
logger.debug("post_data = {}"
|
|
1219
|
+
logger.debug(f"post_data = {post_data}")
|
|
1207
1220
|
return self.__handle_start_analysis(
|
|
1208
1221
|
post_data, ignore_warnings=ignore_warnings
|
|
1209
1222
|
)
|
|
@@ -1245,8 +1258,8 @@ class Project:
|
|
|
1245
1258
|
|
|
1246
1259
|
logger = logging.getLogger(logger_name)
|
|
1247
1260
|
if n_calls > call_limit:
|
|
1248
|
-
logger.error("__handle_start_analysis_response called itself more\
|
|
1249
|
-
than {} times: aborting."
|
|
1261
|
+
logger.error(f"__handle_start_analysis_response called itself more\
|
|
1262
|
+
than {n_calls} times: aborting.")
|
|
1250
1263
|
return None
|
|
1251
1264
|
|
|
1252
1265
|
try:
|
|
@@ -1319,7 +1332,7 @@ class Project:
|
|
|
1319
1332
|
new_post, ignore_warnings=ignore_warnings, n_calls=n_calls
|
|
1320
1333
|
)
|
|
1321
1334
|
except platform.ActionFailedError as e:
|
|
1322
|
-
logger.error("Unable to start the analysis: {}"
|
|
1335
|
+
logger.error(f"Unable to start the analysis: {e}")
|
|
1323
1336
|
return None
|
|
1324
1337
|
|
|
1325
1338
|
@staticmethod
|
|
@@ -1346,7 +1359,7 @@ class Project:
|
|
|
1346
1359
|
set to pass or fail.
|
|
1347
1360
|
"""
|
|
1348
1361
|
logger = logging.getLogger(__name__)
|
|
1349
|
-
logger.info("Setting QC status to {}: {}"
|
|
1362
|
+
logger.info(f"Setting QC status to {status}: {comments}")
|
|
1350
1363
|
|
|
1351
1364
|
platform.parse_response(platform.post(
|
|
1352
1365
|
auth=self._account.auth,
|
|
@@ -1359,6 +1372,42 @@ class Project:
|
|
|
1359
1372
|
}
|
|
1360
1373
|
))
|
|
1361
1374
|
|
|
1375
|
+
def get_qc_status(
|
|
1376
|
+
self, patient_secret_name=None, ssid=None, analysis_id=None):
|
|
1377
|
+
"""
|
|
1378
|
+
Gets the session QC status of a session. If the analysis_id is
|
|
1379
|
+
specified, it returns the QC of the
|
|
1380
|
+
analysis instead.
|
|
1381
|
+
|
|
1382
|
+
"""
|
|
1383
|
+
if patient_secret_name and ssid:
|
|
1384
|
+
session = self.get_subjects_metadata(
|
|
1385
|
+
search_criteria={
|
|
1386
|
+
"pars_patient_secret_name": f"string;"
|
|
1387
|
+
f"{patient_secret_name}",
|
|
1388
|
+
"pars_ssid": f"integer;eq|{ssid}"
|
|
1389
|
+
}
|
|
1390
|
+
)
|
|
1391
|
+
to_return = session["qa_status"], session["qa_comments"]
|
|
1392
|
+
elif analysis_id:
|
|
1393
|
+
try:
|
|
1394
|
+
to_return = [
|
|
1395
|
+
analysis["qa_data"] for analysis in self.list_analysis()
|
|
1396
|
+
if analysis["_id"] == analysis_id
|
|
1397
|
+
][0]
|
|
1398
|
+
to_return = to_return["qa_status"], to_return["qa_comments"]
|
|
1399
|
+
except IndexError:
|
|
1400
|
+
# Handle the case where no matching analysis is found
|
|
1401
|
+
to_return = None
|
|
1402
|
+
except Exception as e:
|
|
1403
|
+
# Handle other potential exceptions
|
|
1404
|
+
print(f"An error occurred: {e}")
|
|
1405
|
+
to_return = None
|
|
1406
|
+
else:
|
|
1407
|
+
raise Exception(f"Must specify {patient_secret_name} and "
|
|
1408
|
+
f"{ssid} or {analysis_id}.")
|
|
1409
|
+
return to_return
|
|
1410
|
+
|
|
1362
1411
|
def start_multiple_analyses(
|
|
1363
1412
|
self,
|
|
1364
1413
|
script_name,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
qmenta/__init__.py,sha256=jv2YF__bseklT3OWEzlqJ5qE24c4aWd5F4r0TTjOrWQ,65
|
|
2
2
|
qmenta/client/Account.py,sha256=MEljEy9cmg2uP2FG1d3TZAgfj66EE2_3PQAZ9rvpCXY,9647
|
|
3
3
|
qmenta/client/File.py,sha256=ZgvSqejIosUt4uoX7opUnPnp5XGEaJNMRwFC0mQVB8k,5344
|
|
4
|
-
qmenta/client/Project.py,sha256=
|
|
4
|
+
qmenta/client/Project.py,sha256=rxOd03sZXCrZjHbxQlgV7qbEXc2STX-sTSXprBKkIOA,48357
|
|
5
5
|
qmenta/client/Subject.py,sha256=lhxxVdQ6d-GNoQC8mrJwa4L1f44nJc4PcJtDspmKN7I,8756
|
|
6
6
|
qmenta/client/__init__.py,sha256=AjTojBhZeW5nl0i605KS8S1Gl5tPNc1hdzD47BGNfoI,147
|
|
7
7
|
qmenta/client/utils.py,sha256=5DK2T_HQprrCwLS0Ycm2CjseaYmAUKaJkJvYoW-Rqzc,2479
|
|
8
|
-
qmenta_client-1.1.
|
|
9
|
-
qmenta_client-1.1.
|
|
10
|
-
qmenta_client-1.1.
|
|
8
|
+
qmenta_client-1.1.dev1230.dist-info/METADATA,sha256=GVsXH4eCCog-jbYRrB-vthtUbOnvsemdnc-yAmeNdak,609
|
|
9
|
+
qmenta_client-1.1.dev1230.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
10
|
+
qmenta_client-1.1.dev1230.dist-info/RECORD,,
|