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 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 / (bytes_in_mb), total / (bytes_in_mb))
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 type(project_id) == str:
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 this parameters and its properties.
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: {}".format(title))
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
- "The analysis identifier must be its name or an integer"
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
- "multiple analyses with name {!r} found".format(
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
- "multiple containers for subject {!r} found".format(
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"t have
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"t have any tags
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
- files_in_container = self.list_container_files(container_id)
585
- files_not_in_container = filter(lambda f: f not in files_in_container,
586
- filenames)
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 {}: {}".format(
591
- container_id, ", ".join(files_not_in_container))
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
- "Subject with name {} already exists in project!".format(
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
- name : str
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
- request_headers["Content-Type"] = "application/zip"
833
- request_headers["Content-Range"] = range_str
834
- request_headers["Session-ID"] = str(session_id)
835
- request_headers["Content-Length"] = str(length)
836
- request_headers["Content-Disposition"] = disposition
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
- data_of_scan : str
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=%s" % 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 retireve, either the numeric ID or the name
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 {}".format(project_id) +
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 = {}".format(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.".format(n_calls))
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: {}".format(e))
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 {}: {}".format(status, comments))
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,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: qmenta-client
3
- Version: 1.1.dev1217
3
+ Version: 1.1.dev1230
4
4
  Summary: Python client lib to interact with the QMENTA platform.
5
5
  Home-page: https://www.qmenta.com/
6
6
  Author: QMENTA
@@ -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=ugxLNnfYBojylOTfSlCpaDGA9_8DwSAB2pONOYA3Sbw,46445
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.dev1217.dist-info/METADATA,sha256=u1nGnyNgNrpjs3T1kBHOEw7_cQxUdd7Os8Chlqu0Vsw,609
9
- qmenta_client-1.1.dev1217.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
10
- qmenta_client-1.1.dev1217.dist-info/RECORD,,
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.8.1
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any