qmenta-client 1.1.dev1324__py3-none-any.whl → 1.1.dev1337__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
@@ -200,14 +200,45 @@ def wrap_search_criteria(search_criteria={}):
200
200
  return modality, tags, file_metadata
201
201
 
202
202
 
203
+ def convert_qc_value_to_qcstatus(value):
204
+ """
205
+ Convert input string to QCStatus class.
206
+
207
+ Parameters
208
+ ----------
209
+ value : str
210
+ Value to convert.
211
+
212
+ Returns
213
+ -------
214
+ QCStatus or Bool
215
+ QCStatus.PASS, QCStatus.FAIL or QCStatus.UNDETERMINED
216
+ False if the Value cannot be convered.
217
+ """
218
+ logger = logging.getLogger(logger_name)
219
+ if value == "pass":
220
+ return QCStatus.PASS
221
+ elif value == "fail":
222
+ return QCStatus.FAIL
223
+ elif value == "":
224
+ return QCStatus.UNDERTERMINED
225
+ else:
226
+ logger.error(f"The input value '{value}' cannot be converted "
227
+ f"to class QCStatus.")
228
+ return False
229
+
230
+
203
231
  class QCStatus(Enum):
204
232
  """
205
233
  Enum with the following options:
206
- FAIL, PASS
234
+ FAIL, PASS, UNDERTERMINED
235
+ that are the possible options for the QA/QC status of both
236
+ analysis and session.
207
237
  """
208
238
 
209
239
  PASS = "pass"
210
240
  FAIL = "fail"
241
+ UNDERTERMINED = ""
211
242
 
212
243
 
213
244
  class Project:
@@ -1841,7 +1872,8 @@ class Project:
1841
1872
  modalities.append(modality)
1842
1873
  return modalities
1843
1874
 
1844
- def set_qc_status(self, analysis_id, status=QCStatus.PASS, comments=""):
1875
+ def set_qc_status_analysis(self, analysis_id,
1876
+ status=QCStatus.UNDERTERMINED, comments=""):
1845
1877
  """
1846
1878
  Changes the analysis QC status.
1847
1879
 
@@ -1850,150 +1882,257 @@ class Project:
1850
1882
  analysis_id : int
1851
1883
  Analysis ID number
1852
1884
  status : QCStatus
1853
- QCStatus.PASS or QCStatus.FAIL
1885
+ QCStatus.PASS, QCStatus.FAIL or QCStatus.UNDETERMINED
1854
1886
  comments : str, optional
1855
- Additional comments explaining why the QC status has been
1856
- set to pass or fail.
1887
+ Additional comments explaining why the reasoning of setting the
1888
+ QC status to such state.
1889
+
1890
+ Returns
1891
+ -------
1892
+ bool
1893
+ True if the QC status was correctly changed, False otherwise.
1857
1894
  """
1895
+
1858
1896
  logger = logging.getLogger(__name__)
1859
1897
  logger.info(f"Setting QC status to {status}: {comments}")
1860
1898
 
1861
- platform.parse_response(
1862
- platform.post(
1863
- auth=self._account.auth,
1864
- endpoint="projectset_manager/set_qa_status",
1865
- data={"item_ids": analysis_id, "status": status.value, "comments": comments, "entity": "analysis"},
1899
+ if not isinstance(status, QCStatus):
1900
+ raise ValueError("Status should be type 'QCStatus'.")
1901
+
1902
+ try:
1903
+ analysis_id = str(int(analysis_id))
1904
+ except ValueError:
1905
+ raise ValueError(f"analysis_id: '{analysis_id}' not valid. " f"Must be convertible to int.")
1906
+
1907
+ try:
1908
+ platform.parse_response(
1909
+ platform.post(
1910
+ auth=self._account.auth,
1911
+ endpoint="projectset_manager/set_qa_status",
1912
+ data={"item_ids": analysis_id, "status": status.value,
1913
+ "comments": str(comments), "entity": "analysis"},
1914
+ )
1866
1915
  )
1867
- )
1916
+ except Exception:
1917
+ logger.error(f"It was not possible to change the QC status of"
1918
+ f"Analysis ID: {analysis_id}")
1919
+ return False
1920
+ return True
1868
1921
 
1869
- def get_qc_status(self, patient_secret_name=None, ssid=None, analysis_id=None):
1922
+ def set_qc_status_subject(self, patient_id,
1923
+ status=QCStatus.UNDERTERMINED, comments=""):
1870
1924
  """
1871
- Gets the session QC status of a session. If the analysis_id is
1872
- specified, it returns the QC of the
1873
- analysis instead.
1925
+ Changes the QC status of a Patient ID (equivalent to a
1926
+ Subject ID/Session ID).
1927
+
1928
+ Parameters
1929
+ ----------
1930
+ patient_id : int
1931
+ Patient ID number of the session.
1932
+ status : QCStatus
1933
+ QCStatus.PASS, QCStatus.FAIL or QCStatus.UNDETERMINED
1934
+ comments : str, optional
1935
+ Additional comments explaining why the reasoning of setting the
1936
+ QC status to such state.
1874
1937
 
1938
+ Returns
1939
+ -------
1940
+ bool
1941
+ True if the QC status was correctly changed, False otherwise.
1875
1942
  """
1876
- if patient_secret_name and ssid:
1877
- session = self.get_subjects_metadata(
1878
- search_criteria={
1879
- "pars_patient_secret_name": f"string;" f"{patient_secret_name}",
1880
- "pars_ssid": f"integer;eq|{ssid}",
1881
- }
1943
+ logger = logging.getLogger(__name__)
1944
+ logger.info(f"Setting QC status to {status}: {comments}")
1945
+
1946
+ if not isinstance(status, QCStatus):
1947
+ raise ValueError("Status should be type 'QCStatus'.")
1948
+
1949
+ try:
1950
+ patient_id = str(int(patient_id))
1951
+ except ValueError:
1952
+ raise ValueError(f"'patient_id': '{patient_id}' not valid. " f"Must be convertible to int.")
1953
+
1954
+ try:
1955
+ platform.parse_response(
1956
+ platform.post(
1957
+ auth=self._account.auth,
1958
+ endpoint="projectset_manager/set_qa_status",
1959
+ data={"item_ids": patient_id, "status": status.value,
1960
+ "comments": str(comments), "entity": "patients"},
1961
+ )
1882
1962
  )
1883
- to_return = session["qa_status"], session["qa_comments"]
1884
- elif analysis_id:
1885
- try:
1886
- to_return = [
1887
- analysis["qa_data"] for analysis in self.list_analysis() if analysis["_id"] == analysis_id
1888
- ][0]
1889
- to_return = to_return["qa_status"], to_return["qa_comments"]
1890
- except IndexError:
1891
- # Handle the case where no matching analysis is found
1892
- to_return = None
1893
- except Exception as e:
1894
- # Handle other potential exceptions
1895
- print(f"An error occurred: {e}")
1896
- to_return = None
1897
- else:
1898
- raise Exception(f"Must specify {patient_secret_name} and {ssid} or {analysis_id}.")
1899
- return to_return
1963
+ except Exception:
1964
+ logger.error(f"It was not possible to change the QC status of"
1965
+ f"Patient ID: {patient_id}")
1966
+ return False
1967
+ return True
1900
1968
 
1901
- def start_multiple_analyses(
1902
- self,
1903
- script_name,
1904
- version,
1905
- n_times,
1906
- in_container_id=None,
1907
- analysis_name=None,
1908
- analysis_description=None,
1909
- ignore_warnings=False,
1910
- settings=None,
1911
- tags=None,
1912
- preferred_destination=None,
1913
- ):
1969
+ def get_qc_status_analysis(self, analysis_id):
1914
1970
  """
1915
- Starts multiple times the same analysis on a subject with the same
1916
- settings.
1971
+ Gets the QC status of an anlaysis provided its Analysis ID.
1917
1972
 
1918
1973
  Parameters
1919
1974
  ----------
1920
- script_name : str
1921
- ID of the script to be run.
1922
- version: str
1923
- Version of the script to be run, examples: 1.0, 5.3.4
1924
- n_times: int
1925
- Number of analyses to be scheduled
1926
- in_container_id : int or dict
1927
- The ID of the container to get the data from, or a dictionary with
1928
- one or more container names as keys, and IDs as values.
1929
- Input container names are generally prefixed with "input\\_".
1930
- If not, the prefix will be automatically added.
1931
- analysis_name : str
1932
- Name of the analysis (optional)
1933
- analysis_description : str
1934
- Description of the analysis (optional)
1935
- ignore_warnings : bool
1936
- If False, warnings by server cause failure.
1937
- settings : dict
1938
- The input settings used to run the analysis.
1939
- Use either settings or in_container_id. Input specification
1940
- in the settings dict can be done by using the key "input".
1941
- tags : list[str]
1942
- The tags of the analysis.
1943
- preferred_destination : str
1944
- The machine on which to run the analysis
1975
+ analysis_id : int
1976
+ Analysis ID number
1945
1977
 
1946
- Yields
1978
+ Returns
1947
1979
  -------
1948
- int
1949
- The analysis ID if correctly started, None otherwise.
1980
+ status : QCStatus or False
1981
+ QCStatus.PASS, QCStatus.FAIL or QCStatus.UNDETERMINED
1982
+ False if the status cannot be extracted.
1983
+ comments : str or False
1984
+ Comments defined in the QC Status.
1985
+ False if the comments cannot be extracted.
1950
1986
  """
1951
- logger = logging.getLogger(logger_name)
1952
- for n in range(n_times):
1953
- logger.info(f"Running tool {script_name}:{version} {n + 1}/{n_times}")
1954
- yield self.start_analysis(
1955
- script_name,
1956
- version,
1957
- in_container_id=in_container_id,
1958
- analysis_name=analysis_name,
1959
- analysis_description=analysis_description,
1960
- ignore_warnings=ignore_warnings,
1961
- settings=settings,
1962
- tags=tags,
1963
- preferred_destination=preferred_destination,
1987
+ try:
1988
+ search_criteria = {"id": analysis_id}
1989
+ to_return = self.list_analysis(search_criteria)
1990
+ return convert_qc_value_to_qcstatus(to_return[0]["qa_status"]), to_return[0]["qa_comments"]
1991
+ except IndexError:
1992
+ # Handle the case where no matching analysis is found
1993
+ logging.error(f"No analysis was found with such Analysis ID: '{analysis_id}'.")
1994
+ return False, False
1995
+ except Exception:
1996
+ # Handle other potential exceptions
1997
+ logging.error(f"It was not possible to extract the QC status"
1998
+ f"from Analysis ID: {analysis_id}")
1999
+ return False, False
2000
+
2001
+ def get_qc_status_subject(self, patient_id=None, subject_name=None,
2002
+ ssid=None):
2003
+ """
2004
+ Gets the session QC status via the patient ID or the Subject ID
2005
+ and the Session ID.
2006
+
2007
+ Parameters
2008
+ ----------
2009
+ patient_id : int
2010
+ Patient ID number of the session
2011
+ subject_name : string
2012
+ Subject ID of the session
2013
+ ssid : string
2014
+ Session ID
2015
+
2016
+ Returns
2017
+ -------
2018
+ status : QCStatus or False
2019
+ QCStatus.PASS, QCStatus.FAIL or QCStatus.UNDETERMINED
2020
+ False if the status cannot be extracted.
2021
+ comments : str or False
2022
+ Comments defined in the QC Status.
2023
+ False if the comments cannot be extracted.
2024
+ """
2025
+
2026
+ if patient_id:
2027
+ try:
2028
+ patient_id = int(patient_id)
2029
+ except ValueError:
2030
+ raise ValueError(f"patient_id '{patient_id}' should be an "
2031
+ f"integer.")
2032
+ sessions = self.get_subjects_metadata(search_criteria={})
2033
+ session = [session for session in sessions if int(session["_id"]) == patient_id]
2034
+ if len(session) < 1:
2035
+ logging.error(f"No session was found with Patient ID: "
2036
+ f"'{patient_id}'.")
2037
+ return False, False
2038
+ return convert_qc_value_to_qcstatus(session[0]["qa_status"]), session[0]["qa_comments"]
2039
+ elif subject_name and ssid:
2040
+ session = self.get_subjects_metadata(
2041
+ search_criteria={
2042
+ "pars_patient_secret_name": f"string;{subject_name}",
2043
+ "pars_ssid": f"integer;eq|{ssid}",
2044
+ }
1964
2045
  )
2046
+ if len(session) < 1:
2047
+ logging.error(f"No session was found with Subject ID: "
2048
+ f"'{subject_name}' and Session ID: '{ssid}'.")
2049
+ return False, False
2050
+ return convert_qc_value_to_qcstatus(session[0]["qa_status"]), session[0]["qa_comments"]
2051
+ else:
2052
+ raise ValueError("Either 'patient_id' or 'subject_name' and 'ssid'"
2053
+ " must not be empty.")
1965
2054
 
1966
- def set_project_qa_rules(self, rules_file_path, guidance_text=""):
2055
+ def set_project_pa_rules(self, rules_file_path, guidance_text=""):
1967
2056
  """
1968
- Logs in to the Qmenta platform, retrieves the project ID based on the project name,
1969
- and updates the project's QA rules using the provided rules file.
2057
+ Updates the active project's protocol adherence rules using the
2058
+ provided rules file.
1970
2059
 
1971
- Args:
1972
- rules_file_path (str): The file path to the JSON file containing the QA rules.
1973
- guidance_text (str): Description of the rules. Only visible for Platform admins.
2060
+ Parameters
2061
+ ----------
2062
+ rules_file_path : str
2063
+ The file path to the JSON file containing the protocol
2064
+ adherence rules.
2065
+ guidance_text : str
2066
+ Description of the protocol adherence rules.
1974
2067
 
1975
- Returns:
1976
- bool: True if the rules were set successfully, False otherwise.
2068
+ Returns
2069
+ -------
2070
+ bool: True if the protocol adherence rules were set successfully,
2071
+ False otherwise.
1977
2072
  """
2073
+ logger = logging.getLogger(logger_name)
1978
2074
  # Read the rules from the JSON file
1979
2075
  try:
1980
2076
  with open(rules_file_path, "r") as fr:
1981
2077
  rules = json.load(fr)
1982
2078
  except FileNotFoundError:
1983
- print(f"ERROR: Rules file '{rules_file_path}' not found.")
2079
+ logger.error(f"Pprotocol adherence rule file '{rules_file_path}' "
2080
+ f"not found.")
1984
2081
  return False
1985
2082
 
1986
2083
  # Update the project's QA rules
1987
- res = platform.post(
2084
+ res = platform.parse_response(platform.post(
1988
2085
  auth=self._account.auth,
1989
2086
  endpoint="projectset_manager/set_session_qa_requirements",
1990
2087
  data={"project_id": self._project_id, "rules": json.dumps(rules), "guidance_text": guidance_text},
1991
- )
2088
+ ))
1992
2089
 
1993
- if res.json().get("success") == 1:
1994
- print("Rules set up successfully!")
1995
- return True
1996
- else:
1997
- print("ERROR setting the rules")
1998
- print(res.json())
2090
+ if not res.get("success") == 1:
2091
+ logger.error("There was an error setting up the protocol "
2092
+ "adherence rules.")
2093
+ logger.error(platform.parse_response(res))
2094
+ return False
2095
+
2096
+ return True
2097
+
2098
+ def get_project_pa_rules(self, rules_file_path):
2099
+ """
2100
+ Retrive the active project's protocol adherence rules
2101
+
2102
+ Parameters
2103
+ ----------
2104
+ rules_file_path : str
2105
+ The file path to the JSON file to store the protocol adherence
2106
+ rules.
2107
+
2108
+ Returns
2109
+ -------
2110
+ guidance_text : str
2111
+ Description of the protocol adherence rules,
2112
+ False if extraction of the protocol adhernece rules is not
2113
+ possible.
2114
+ """
2115
+ logger = logging.getLogger(logger_name)
2116
+
2117
+ # Update the project's QA rules
2118
+ res = platform.parse_response(platform.post(
2119
+ auth=self._account.auth,
2120
+ endpoint="projectset_manager/get_session_qa_requirements",
2121
+ data={"project_id": self._project_id},
2122
+ ))
2123
+
2124
+ if "rules" not in res:
2125
+ logger.error(f"There was an error extracting the protocol "
2126
+ f"adherence rules from {self._project_name}.")
2127
+ logger.error(platform.parse_response(res))
1999
2128
  return False
2129
+
2130
+ try:
2131
+ with open(rules_file_path, "w") as fr:
2132
+ json.dump(res["rules"], fr, indent=4)
2133
+ except FileNotFoundError:
2134
+ logger.error(f"Protocol adherence rules could not be exported"
2135
+ f"to file: '{rules_file_path}'.")
2136
+ return False
2137
+
2138
+ return res["guidance_text"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qmenta-client
3
- Version: 1.1.dev1324
3
+ Version: 1.1.dev1337
4
4
  Summary: Python client lib to interact with the QMENTA platform.
5
5
  Author: QMENTA
6
6
  Author-email: dev@qmenta.com
@@ -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=9a6v7-H6BxU-2EykaWnFhW61GZijDB-XWsYzPdzWxz4,70398
4
+ qmenta/client/Project.py,sha256=XzolIEPQzUWPelWtv67fiYvLGXp7bLRfH2-Ckvgl8Ao,75153
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.dev1324.dist-info/METADATA,sha256=yDhr3jCEwhPFFSWqIdJUeaZtj10Y3GXyEbAq7fDj7UQ,672
9
- qmenta_client-1.1.dev1324.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
10
- qmenta_client-1.1.dev1324.dist-info/RECORD,,
8
+ qmenta_client-1.1.dev1337.dist-info/METADATA,sha256=Epl4svIqv_lvXPjjfBh5zAU02b5i_sq1z-ZptA0c58o,672
9
+ qmenta_client-1.1.dev1337.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
10
+ qmenta_client-1.1.dev1337.dist-info/RECORD,,