qmenta-client 1.1.dev1245__py3-none-any.whl → 1.1.dev1289__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 +341 -109
- {qmenta_client-1.1.dev1245.dist-info → qmenta_client-1.1.dev1289.dist-info}/METADATA +1 -1
- {qmenta_client-1.1.dev1245.dist-info → qmenta_client-1.1.dev1289.dist-info}/RECORD +4 -4
- {qmenta_client-1.1.dev1245.dist-info → qmenta_client-1.1.dev1289.dist-info}/WHEEL +0 -0
qmenta/client/Project.py
CHANGED
|
@@ -11,7 +11,6 @@ from enum import Enum
|
|
|
11
11
|
from qmenta.client import Account
|
|
12
12
|
from qmenta.core import errors
|
|
13
13
|
from qmenta.core import platform
|
|
14
|
-
from .Subject import Subject
|
|
15
14
|
|
|
16
15
|
if sys.version_info[0] == 3:
|
|
17
16
|
# Note: this branch & variable is only needed for python 2/3 compatibility
|
|
@@ -161,45 +160,137 @@ class Project:
|
|
|
161
160
|
dict
|
|
162
161
|
A list of dictionary of {"metadata_name": "metadata_value"}
|
|
163
162
|
"""
|
|
164
|
-
return self.get_subjects_metadata(
|
|
163
|
+
return self.get_subjects_metadata()
|
|
165
164
|
|
|
166
|
-
def get_subjects_metadata(self,
|
|
165
|
+
def get_subjects_metadata(self, search_criteria={}, items=(0, 9999)):
|
|
167
166
|
"""
|
|
168
|
-
List all
|
|
167
|
+
List all subjects data from the selected project that meet the defined
|
|
168
|
+
search criteria.
|
|
169
|
+
|
|
169
170
|
Parameters
|
|
170
171
|
----------
|
|
171
|
-
cache: bool
|
|
172
|
-
Whether to use the cached metadata or not
|
|
173
|
-
|
|
174
172
|
search_criteria: dict
|
|
175
173
|
Each element is a string and is built using the formatting
|
|
176
|
-
|
|
174
|
+
"type;value", or "type;operation|value"
|
|
175
|
+
|
|
176
|
+
Complete search_criteria Dictionary Explanation:
|
|
177
|
+
|
|
178
|
+
search_criteria = {
|
|
179
|
+
"pars_patient_secret_name": "string;SUBJECTID",
|
|
180
|
+
"pars_ssid": "integer;OPERATOR|SSID",
|
|
181
|
+
"pars_modalities": "string;MODALITY",
|
|
182
|
+
"pars_tags": "tags;TAGS",
|
|
183
|
+
"pars_age_at_scan": "integer;OPERATOR|AGE_AT_SCAN",
|
|
184
|
+
"pars_[dicom]_KEY": "KEYTYPE;KEYVALUE",
|
|
185
|
+
"pars_PROJECTMETADATA": "METADATATYPE;METADATAVALUE",
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
Where:
|
|
189
|
+
"pars_patient_secret_name": Applies the search to the 'Subject ID'.
|
|
190
|
+
SUBJECTID is a comma separated list of strings.
|
|
191
|
+
"pars_ssid": Applies the search to the 'Session ID'.
|
|
192
|
+
SSID is an integer.
|
|
193
|
+
OPERATOR is the operator to apply. One of:
|
|
194
|
+
- Equal: eq
|
|
195
|
+
- Different Than: ne
|
|
196
|
+
- Greater Than: gt
|
|
197
|
+
- Greater/Equal To: gte
|
|
198
|
+
- Lower Than: lt
|
|
199
|
+
- Lower/Equal To: lte
|
|
200
|
+
|
|
201
|
+
"pars_modalities": Applies the search to the file 'Modalities'
|
|
202
|
+
available within each Subject ID.
|
|
203
|
+
MODALITY is a comma separated list of string.
|
|
204
|
+
"pars_tags": Applies the search to the file 'Tags' available within
|
|
205
|
+
each Subject ID and to the subject-level 'Tags'.
|
|
206
|
+
TAGS is a comma separated list of strings.
|
|
207
|
+
"pars_age_at_scan": Applies the search to the 'age_at_scan' metadata
|
|
208
|
+
field.
|
|
209
|
+
AGE_AT_SCAN is an integer.
|
|
210
|
+
"pars_[dicom]_KEY": Applies the search to the metadata fields
|
|
211
|
+
available within each file. KEY must be one of the
|
|
212
|
+
metadata keys of the files. The full list of KEYS is shown above via
|
|
213
|
+
'file_m["metadata"]["info"].keys()'.
|
|
214
|
+
KEYTYPE is the type of the KEY. One of:
|
|
215
|
+
- integer
|
|
216
|
+
- string
|
|
217
|
+
- list
|
|
218
|
+
|
|
219
|
+
if 'integer' you must also include an OPERATOR
|
|
220
|
+
(i.e., "integer;OPERATOR|KEYVALUE").
|
|
221
|
+
KEYVALUE is the expected value of the KEY.
|
|
222
|
+
"pars_[dicom]_PROJECTMETADATA": Applies to the metadata defined
|
|
223
|
+
within the 'Metadata Manager' of the project.
|
|
224
|
+
PROJECTMETADATA is the ID of the metadata field.
|
|
225
|
+
METADATATYPE is the type of the metadata field. One of:
|
|
226
|
+
- string
|
|
227
|
+
- integer
|
|
228
|
+
- list
|
|
229
|
+
- decimal
|
|
230
|
+
- single_option
|
|
231
|
+
- multiple_option
|
|
232
|
+
|
|
233
|
+
if 'integer' or 'decimal' you must also include an OPERATOR
|
|
234
|
+
(i.e., "integer;OPERATOR|METADATAVALUE").
|
|
235
|
+
KEYVALUE is the expected value of the metadata.
|
|
236
|
+
|
|
237
|
+
1) Example:
|
|
238
|
+
search_criteria = {
|
|
239
|
+
"pars_patient_secret_name": "string;abide",
|
|
240
|
+
"pars_ssid": "integer;eq|2"
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
2) Example:
|
|
244
|
+
search_criteria = {
|
|
245
|
+
"pars_modalities": "string;T1",
|
|
246
|
+
"pars_tags": "tags;flair",
|
|
247
|
+
"pars_[dicom]_Manufacturer": "string;ge",
|
|
248
|
+
"pars_[dicom]_FlipAngle": "integer;gt|5",
|
|
249
|
+
}
|
|
177
250
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
251
|
+
Note the search criteria applies to all the files included within a
|
|
252
|
+
session. Hence, it does not imply that all the criteria conditions
|
|
253
|
+
are applied to the same files. In example 2) above, it means that
|
|
254
|
+
any Subject ID/Session ID that has a file classified with a 'T1'
|
|
255
|
+
modality, a file with a 'flair' tag, a file whose Manufacturer
|
|
256
|
+
contains 'ge', and a file whose FlipAngle is greater than '5º' will
|
|
257
|
+
be selected.
|
|
181
258
|
|
|
182
259
|
Returns
|
|
183
260
|
-------
|
|
184
261
|
dict
|
|
185
262
|
A list of dictionary of {"metadata_name": "metadata_value"}
|
|
263
|
+
|
|
186
264
|
"""
|
|
187
265
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
266
|
+
assert len(items) == 2, f"The number of elements in items " \
|
|
267
|
+
f"'{len(items)}' should be equal to two."
|
|
268
|
+
assert all([isinstance(item, int) for item in items]), \
|
|
269
|
+
f"All items elements '{items}' should be integers."
|
|
270
|
+
|
|
271
|
+
assert all([key[:5] == "pars_" for key in search_criteria.keys()]), \
|
|
272
|
+
f"All keys of the search_criteria dictionary " \
|
|
273
|
+
f"'{search_criteria.keys()}' must start with 'pars_'."
|
|
274
|
+
|
|
275
|
+
operator_list = ["eq", "ne", "gt", "gte", "lt", "lte"]
|
|
276
|
+
for key, value in search_criteria.items():
|
|
277
|
+
if value.split(";")[0] in ["integer", "decimal"]:
|
|
278
|
+
assert value.split(";")[1].split("|")[0] in operator_list, \
|
|
279
|
+
f"Search criteria of type '{value.split(';')[0]}' must " \
|
|
280
|
+
f"include an operator ({', '.join(operator_list)})."
|
|
281
|
+
|
|
282
|
+
content = platform.parse_response(platform.post(
|
|
283
|
+
self._account.auth, "patient_manager/get_patient_list",
|
|
284
|
+
data=search_criteria,
|
|
285
|
+
headers={"X-Range": f"items={items[0]}-{items[1]}"}
|
|
286
|
+
))
|
|
197
287
|
return content
|
|
198
288
|
|
|
199
289
|
@property
|
|
200
290
|
def subjects(self):
|
|
201
291
|
"""
|
|
202
|
-
Return the list of subject names from the selected
|
|
292
|
+
Return the list of subject names (Subject ID) from the selected
|
|
293
|
+
project.
|
|
203
294
|
|
|
204
295
|
:return: a list of subject names
|
|
205
296
|
:rtype: List(Strings)
|
|
@@ -211,12 +302,13 @@ class Project:
|
|
|
211
302
|
|
|
212
303
|
def check_subject_name(self, subject_name):
|
|
213
304
|
"""
|
|
214
|
-
Check if a given subject name exists in the selected
|
|
305
|
+
Check if a given subject name (Subject ID) exists in the selected
|
|
306
|
+
project.
|
|
215
307
|
|
|
216
308
|
Parameters
|
|
217
309
|
----------
|
|
218
310
|
subject_name : str
|
|
219
|
-
|
|
311
|
+
Subject ID of the subject to check
|
|
220
312
|
|
|
221
313
|
Returns
|
|
222
314
|
-------
|
|
@@ -403,48 +495,81 @@ class Project:
|
|
|
403
495
|
data=search_condition
|
|
404
496
|
))
|
|
405
497
|
|
|
406
|
-
def
|
|
407
|
-
|
|
498
|
+
def get_subject_container_id(self, subject_name, ssid):
|
|
499
|
+
"""
|
|
500
|
+
Given a Subject ID and Session ID, return its Container ID.
|
|
501
|
+
|
|
502
|
+
Parameters
|
|
503
|
+
----------
|
|
504
|
+
subject_name : str
|
|
505
|
+
Subject ID of the subject in the project.
|
|
506
|
+
ssid : str
|
|
507
|
+
Session ID of the subject in the project.
|
|
508
|
+
|
|
509
|
+
Returns
|
|
510
|
+
-------
|
|
511
|
+
int or bool
|
|
512
|
+
The Container ID of the subject in the project, or False if
|
|
513
|
+
the subject is not found.
|
|
514
|
+
"""
|
|
515
|
+
|
|
516
|
+
search_criteria = {
|
|
408
517
|
"s_n": subject_name,
|
|
518
|
+
"ssid": ssid
|
|
409
519
|
}
|
|
410
520
|
response = self.list_input_containers(
|
|
411
|
-
|
|
521
|
+
search_criteria=search_criteria
|
|
412
522
|
)
|
|
413
523
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
else:
|
|
420
|
-
return None
|
|
524
|
+
for subject in response:
|
|
525
|
+
if subject["patient_secret_name"] == subject_name and \
|
|
526
|
+
subject["ssid"] == ssid:
|
|
527
|
+
return subject["container_id"]
|
|
528
|
+
return False
|
|
421
529
|
|
|
422
|
-
def list_input_containers(self,
|
|
530
|
+
def list_input_containers(self, search_criteria={}, items=(0, 9999)):
|
|
423
531
|
"""
|
|
424
|
-
|
|
532
|
+
Retrieve the list of input containers available to the user under a
|
|
533
|
+
certain search criteria.
|
|
425
534
|
|
|
426
535
|
Parameters
|
|
427
536
|
----------
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
537
|
+
search_criteria : dict
|
|
538
|
+
Each element is a string and is built using the formatting
|
|
539
|
+
"type;value".
|
|
540
|
+
|
|
541
|
+
List of possible keys:
|
|
542
|
+
d_n: container_name # TODO: WHAT IS THIS???
|
|
543
|
+
s_n: subject_id
|
|
544
|
+
Subject ID of the subject in the platform.
|
|
545
|
+
ssid: session_id
|
|
546
|
+
Session ID of the subejct in the platform.
|
|
547
|
+
from_d: from date
|
|
548
|
+
Starting date in which perform the search. Format: DD.MM.YYYY
|
|
549
|
+
to_d: to date
|
|
550
|
+
End date in which perform the search. Format: DD.MM.YYYY
|
|
551
|
+
sets: data sets (modalities) # TODO: WHAT IS THIS???
|
|
552
|
+
|
|
553
|
+
items: Tuple(int, int)
|
|
554
|
+
Starting and ending element of the search.
|
|
436
555
|
|
|
437
556
|
Returns
|
|
438
557
|
-------
|
|
439
558
|
dict
|
|
440
|
-
|
|
441
|
-
|
|
559
|
+
List of containers, each a dictionary containing the following
|
|
560
|
+
information:
|
|
561
|
+
{"container_name", "container_id", "patient_secret_name", "ssid"}
|
|
442
562
|
"""
|
|
443
563
|
|
|
444
|
-
|
|
564
|
+
assert len(items) == 2, f"The number of elements in items " \
|
|
565
|
+
f"'{len(items)}' should be equal to two."
|
|
566
|
+
assert all([isinstance(item, int) for item in items]), \
|
|
567
|
+
f"All items elements '{items}' should be integers."
|
|
568
|
+
|
|
445
569
|
response = platform.parse_response(platform.post(
|
|
446
570
|
self._account.auth, "file_manager/get_container_list",
|
|
447
|
-
data=
|
|
571
|
+
data=search_criteria,
|
|
572
|
+
headers={"X-Range": f"items={items[0]}-{items[1]}"}
|
|
448
573
|
))
|
|
449
574
|
containers = [
|
|
450
575
|
{
|
|
@@ -545,12 +670,15 @@ class Project:
|
|
|
545
670
|
Returns
|
|
546
671
|
-------
|
|
547
672
|
dict
|
|
548
|
-
Dictionary with the metadata.
|
|
673
|
+
Dictionary with the metadata. False otherwise.
|
|
549
674
|
"""
|
|
550
675
|
all_metadata = self.list_container_files_metadata(container_id)
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
676
|
+
if all_metadata:
|
|
677
|
+
for file_meta in all_metadata:
|
|
678
|
+
if file_meta["name"] == filename:
|
|
679
|
+
return file_meta
|
|
680
|
+
else:
|
|
681
|
+
return False
|
|
554
682
|
|
|
555
683
|
def change_file_metadata(self, container_id, filename, modality, tags):
|
|
556
684
|
"""
|
|
@@ -673,16 +801,17 @@ class Project:
|
|
|
673
801
|
container_id, zip_name))
|
|
674
802
|
return True
|
|
675
803
|
|
|
676
|
-
def get_subject_id(self, subject_name,
|
|
804
|
+
def get_subject_id(self, subject_name, ssid):
|
|
677
805
|
"""
|
|
678
|
-
Given a
|
|
806
|
+
Given a Subject ID and Session ID, return its Patient ID in the
|
|
807
|
+
project.
|
|
679
808
|
|
|
680
809
|
Parameters
|
|
681
810
|
----------
|
|
682
811
|
subject_name : str
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
812
|
+
Subject ID of the subject in the project.
|
|
813
|
+
ssid : str
|
|
814
|
+
Session ID of the subject in the project.
|
|
686
815
|
|
|
687
816
|
Returns
|
|
688
817
|
-------
|
|
@@ -691,37 +820,12 @@ class Project:
|
|
|
691
820
|
the subject is not found.
|
|
692
821
|
"""
|
|
693
822
|
|
|
694
|
-
for user in self.get_subjects_metadata(
|
|
695
|
-
if user["patient_secret_name"] == subject_name
|
|
823
|
+
for user in self.get_subjects_metadata():
|
|
824
|
+
if user["patient_secret_name"] == str(subject_name) and \
|
|
825
|
+
user["ssid"] == str(ssid):
|
|
696
826
|
return int(user["_id"])
|
|
697
827
|
return False
|
|
698
828
|
|
|
699
|
-
def get_subject(self, subject_name, cache=True):
|
|
700
|
-
"""
|
|
701
|
-
Return a subject object, representing a subject from the project.
|
|
702
|
-
|
|
703
|
-
Parameters
|
|
704
|
-
----------
|
|
705
|
-
subject_name : str
|
|
706
|
-
Name of the subject.
|
|
707
|
-
cache: bool
|
|
708
|
-
Whether to use the cached metadata or not
|
|
709
|
-
|
|
710
|
-
Returns
|
|
711
|
-
-------
|
|
712
|
-
Subject or bool
|
|
713
|
-
A Subject instance representing the desired subject, or
|
|
714
|
-
False if the subject was not found.
|
|
715
|
-
|
|
716
|
-
"""
|
|
717
|
-
subject_id = self.get_subject_id(subject_name, cache=cache)
|
|
718
|
-
if subject_id is False:
|
|
719
|
-
return False
|
|
720
|
-
subj = Subject(subject_name)
|
|
721
|
-
subj.subject_id = subject_id
|
|
722
|
-
subj.project = self
|
|
723
|
-
return subj
|
|
724
|
-
|
|
725
829
|
def add_subject(self, subject):
|
|
726
830
|
"""
|
|
727
831
|
Add a subject to the project.
|
|
@@ -757,18 +861,114 @@ class Project:
|
|
|
757
861
|
"Subject {0} was successfully created".format(subject.name))
|
|
758
862
|
return True
|
|
759
863
|
|
|
760
|
-
def
|
|
864
|
+
def change_subject_metadata(self, patient_id, subject_name, ssid, tags,
|
|
865
|
+
age_at_scan, metadata):
|
|
866
|
+
"""
|
|
867
|
+
Change the Subject ID, Session ID, Tags, Age at Scan and Metadata of
|
|
868
|
+
the session with Patient ID
|
|
869
|
+
|
|
870
|
+
Parameters
|
|
871
|
+
----------
|
|
872
|
+
patient_id : Integer
|
|
873
|
+
Patient ID representing the session to modify.
|
|
874
|
+
subject_name : String
|
|
875
|
+
Represents the new Subject ID.
|
|
876
|
+
ssid : String
|
|
877
|
+
Represents the new Session ID.
|
|
878
|
+
tags : list of strings in lowercase
|
|
879
|
+
Represents the new tags of the session.
|
|
880
|
+
age_at_scan : Integer
|
|
881
|
+
Represents the new Age at Scan of the Session.
|
|
882
|
+
metadata : Dictionary
|
|
883
|
+
Each pair key/value representing the new metadata values.
|
|
884
|
+
|
|
885
|
+
The keys must either all start with "md\\_" or none start
|
|
886
|
+
with "md\\_".
|
|
887
|
+
|
|
888
|
+
The key represents the ID of the metadata field.
|
|
889
|
+
|
|
890
|
+
Returns
|
|
891
|
+
-------
|
|
892
|
+
bool
|
|
893
|
+
True if correctly modified, False otherwise
|
|
894
|
+
"""
|
|
895
|
+
logger = logging.getLogger(logger_name)
|
|
896
|
+
|
|
897
|
+
try:
|
|
898
|
+
patient_id = str(int(patient_id))
|
|
899
|
+
except ValueError:
|
|
900
|
+
raise ValueError(f"'patient_id': '{patient_id}' not valid. "
|
|
901
|
+
f"Must be convertible to int.")
|
|
902
|
+
|
|
903
|
+
assert isinstance(tags, list) and \
|
|
904
|
+
all(isinstance(item, str) for item in tags), \
|
|
905
|
+
f"tags: '{tags}' should be a list of strings."
|
|
906
|
+
tags = [tag.lower() for tag in tags]
|
|
907
|
+
|
|
908
|
+
assert subject_name is not None and subject_name != "", \
|
|
909
|
+
"subject_name must be a non empty string."
|
|
910
|
+
assert ssid is not None and ssid != "", \
|
|
911
|
+
"ssid must be a non empty string."
|
|
912
|
+
|
|
913
|
+
try:
|
|
914
|
+
age_at_scan = str(int(age_at_scan)) if age_at_scan else None
|
|
915
|
+
except ValueError:
|
|
916
|
+
raise ValueError(f"age_at_scan: '{age_at_scan}' not valid. "
|
|
917
|
+
f"Must be an integer.")
|
|
918
|
+
|
|
919
|
+
assert isinstance(metadata, dict), \
|
|
920
|
+
f"metadata: '{metadata}' should be a dictionary."
|
|
921
|
+
|
|
922
|
+
assert all("md_" == key[:3] for key in metadata.keys()) or \
|
|
923
|
+
all("md_" != key[:3] for key in metadata.keys()), \
|
|
924
|
+
f"metadata: '{metadata}' must be a dictionary whose keys " \
|
|
925
|
+
f"are either all starting with 'md_' or none."
|
|
926
|
+
|
|
927
|
+
metadata_keys = self.metadata_parameters.keys()
|
|
928
|
+
assert \
|
|
929
|
+
all([key[3:] in metadata_keys
|
|
930
|
+
if "md_" == key[:3] else key in metadata_keys
|
|
931
|
+
for key in metadata.keys()]), \
|
|
932
|
+
f"Some metadata keys provided ({', '.join(metadata.keys())}) " \
|
|
933
|
+
f"are not available in the project. They can be added via the " \
|
|
934
|
+
f"Metadata Manager via the QMENTA Platform graphical user " \
|
|
935
|
+
f"interface (GUI)."
|
|
936
|
+
|
|
937
|
+
post_data = {
|
|
938
|
+
"patient_id": patient_id,
|
|
939
|
+
"secret_name": str(subject_name),
|
|
940
|
+
"ssid": str(ssid),
|
|
941
|
+
"tags": ",".join(tags),
|
|
942
|
+
"age_at_scan": age_at_scan,
|
|
943
|
+
}
|
|
944
|
+
for key, value in metadata.items():
|
|
945
|
+
id = key[3:] if "md_" == key[:3] else key
|
|
946
|
+
post_data[f"last_vals.{id}"] = value
|
|
947
|
+
|
|
948
|
+
try:
|
|
949
|
+
platform.parse_response(platform.post(
|
|
950
|
+
self._account.auth,
|
|
951
|
+
"patient_manager/upsert_patient",
|
|
952
|
+
data=post_data
|
|
953
|
+
))
|
|
954
|
+
except errors.PlatformError:
|
|
955
|
+
logger.error(f"Patient ID '{patient_id}' could not be modified.")
|
|
956
|
+
return False
|
|
957
|
+
|
|
958
|
+
logger.info(f"Patient ID '{patient_id}' successfully modified.")
|
|
959
|
+
return True
|
|
960
|
+
|
|
961
|
+
def delete_session(self, subject_name, session_id):
|
|
761
962
|
"""
|
|
762
|
-
Delete a session from a subject within a project
|
|
963
|
+
Delete a session from a subject within a project providing the
|
|
964
|
+
Subject ID and Session ID.
|
|
763
965
|
|
|
764
966
|
Parameters
|
|
765
967
|
----------
|
|
766
968
|
subject_name : str
|
|
767
|
-
|
|
969
|
+
Subject ID of the subject
|
|
768
970
|
session_id : int
|
|
769
|
-
The
|
|
770
|
-
cache : bool
|
|
771
|
-
Whether to use the cached metadata or not
|
|
971
|
+
The Session ID of the session that will be deleted
|
|
772
972
|
|
|
773
973
|
Returns
|
|
774
974
|
-------
|
|
@@ -776,31 +976,31 @@ class Project:
|
|
|
776
976
|
True if correctly deleted, False otherwise.
|
|
777
977
|
"""
|
|
778
978
|
logger = logging.getLogger(logger_name)
|
|
779
|
-
all_sessions = self.get_subjects_metadata(
|
|
979
|
+
all_sessions = self.get_subjects_metadata()
|
|
780
980
|
|
|
781
|
-
|
|
981
|
+
session_to_del = [
|
|
782
982
|
s for s in all_sessions if
|
|
783
|
-
s["patient_secret_name"] == subject_name and
|
|
784
|
-
|
|
785
|
-
) == session_id
|
|
983
|
+
s["patient_secret_name"] == subject_name and
|
|
984
|
+
s["ssid"] == session_id
|
|
786
985
|
]
|
|
787
986
|
|
|
788
|
-
if not
|
|
987
|
+
if not session_to_del:
|
|
789
988
|
logger.error(
|
|
790
989
|
f"Session {subject_name}/{session_id} could not be found "
|
|
791
990
|
f"in this project."
|
|
792
991
|
)
|
|
793
992
|
return False
|
|
794
|
-
elif len(
|
|
993
|
+
elif len(session_to_del) > 1:
|
|
795
994
|
raise RuntimeError(
|
|
796
|
-
"Multiple sessions with same
|
|
995
|
+
"Multiple sessions with same Subject ID and Session ID."
|
|
996
|
+
" Contact support."
|
|
797
997
|
)
|
|
798
998
|
else:
|
|
799
999
|
logger.info("{}/{} found (id {})".format(
|
|
800
|
-
subject_name, session_id,
|
|
1000
|
+
subject_name, session_id, session_to_del[0]["_id"]
|
|
801
1001
|
))
|
|
802
1002
|
|
|
803
|
-
session =
|
|
1003
|
+
session = session_to_del[0]
|
|
804
1004
|
|
|
805
1005
|
try:
|
|
806
1006
|
platform.parse_response(platform.post(
|
|
@@ -820,14 +1020,46 @@ class Project:
|
|
|
820
1020
|
)
|
|
821
1021
|
return True
|
|
822
1022
|
|
|
1023
|
+
def delete_session_by_patientid(self, patient_id):
|
|
1024
|
+
"""
|
|
1025
|
+
Delete a session from a subject within a project providing the
|
|
1026
|
+
Patient ID.
|
|
1027
|
+
|
|
1028
|
+
Parameters
|
|
1029
|
+
----------
|
|
1030
|
+
patient_id : str
|
|
1031
|
+
Patient ID of the Session ID/Subject ID
|
|
1032
|
+
|
|
1033
|
+
Returns
|
|
1034
|
+
-------
|
|
1035
|
+
bool
|
|
1036
|
+
True if correctly deleted, False otherwise.
|
|
1037
|
+
"""
|
|
1038
|
+
logger = logging.getLogger(logger_name)
|
|
1039
|
+
|
|
1040
|
+
try:
|
|
1041
|
+
platform.parse_response(platform.post(
|
|
1042
|
+
self._account.auth, "patient_manager/delete_patient",
|
|
1043
|
+
data={
|
|
1044
|
+
"patient_id": str(int(patient_id)), "delete_files": 1
|
|
1045
|
+
}
|
|
1046
|
+
))
|
|
1047
|
+
except errors.PlatformError:
|
|
1048
|
+
logger.error(f"Patient ID {patient_id} could not be deleted.")
|
|
1049
|
+
return False
|
|
1050
|
+
|
|
1051
|
+
logger.info(f"Patient ID {patient_id} successfully deleted.")
|
|
1052
|
+
return True
|
|
1053
|
+
|
|
823
1054
|
def delete_subject(self, subject_name):
|
|
824
1055
|
"""
|
|
825
|
-
Delete a subject from the project.
|
|
1056
|
+
Delete a subject from the project. It deletes all its available
|
|
1057
|
+
sessions only providing the Subject ID.
|
|
826
1058
|
|
|
827
1059
|
Parameters
|
|
828
1060
|
----------
|
|
829
1061
|
subject_name : str
|
|
830
|
-
|
|
1062
|
+
Subject ID of the subject to be deleted.
|
|
831
1063
|
|
|
832
1064
|
Returns
|
|
833
1065
|
-------
|
|
@@ -837,7 +1069,7 @@ class Project:
|
|
|
837
1069
|
|
|
838
1070
|
logger = logging.getLogger(logger_name)
|
|
839
1071
|
# Always fetch the session IDs from the platform before deleting them
|
|
840
|
-
all_sessions = self.get_subjects_metadata(
|
|
1072
|
+
all_sessions = self.get_subjects_metadata()
|
|
841
1073
|
|
|
842
1074
|
sessions_to_del = [
|
|
843
1075
|
s for s in all_sessions if s["patient_secret_name"] == subject_name
|
|
@@ -852,7 +1084,7 @@ class Project:
|
|
|
852
1084
|
return False
|
|
853
1085
|
|
|
854
1086
|
for ssid in [s["ssid"] for s in sessions_to_del]:
|
|
855
|
-
if not self.delete_session(subject_name, ssid
|
|
1087
|
+
if not self.delete_session(subject_name, ssid):
|
|
856
1088
|
return False
|
|
857
1089
|
return True
|
|
858
1090
|
|
|
@@ -937,16 +1169,16 @@ class Project:
|
|
|
937
1169
|
add_to_container_id=0, chunk_size=2 ** 9,
|
|
938
1170
|
split_data=False):
|
|
939
1171
|
"""
|
|
940
|
-
Upload a file to the platform
|
|
1172
|
+
Upload a ZIP file to the platform.
|
|
941
1173
|
|
|
942
1174
|
Parameters
|
|
943
1175
|
----------
|
|
944
1176
|
file_path : str
|
|
945
|
-
Path to the file to upload.
|
|
1177
|
+
Path to the ZIP file to upload.
|
|
946
1178
|
subject_name : str
|
|
947
|
-
Subject to
|
|
1179
|
+
Subject ID of the data to upload in the project in QMENTA Platform.
|
|
948
1180
|
ssid : str
|
|
949
|
-
|
|
1181
|
+
Session ID of the Subject ID (i.e., ID of the timepoint).
|
|
950
1182
|
date_of_scan : str
|
|
951
1183
|
Date of scan/creation of the file
|
|
952
1184
|
description : str
|
|
@@ -956,7 +1188,7 @@ class Project:
|
|
|
956
1188
|
name : str
|
|
957
1189
|
Name of the file in the platform
|
|
958
1190
|
input_data_type : str
|
|
959
|
-
|
|
1191
|
+
qmenta_medical_image_data:3.11
|
|
960
1192
|
add_to_container_id : int
|
|
961
1193
|
ID of the container to which this file should be added (if id > 0)
|
|
962
1194
|
chunk_size : int
|
|
@@ -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=Y0G5vSVODThAL8kGwmtkcZrE49vB2LVlNf2eRrqr8dg,59767
|
|
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.dev1289.dist-info/METADATA,sha256=khcRoMKuV0hhGvxc-9tjMy9RRIXugkzyE5sKZ_PuF4M,672
|
|
9
|
+
qmenta_client-1.1.dev1289.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
|
|
10
|
+
qmenta_client-1.1.dev1289.dist-info/RECORD,,
|
|
File without changes
|