qmenta-sdk-lib 2.2.dev3493__tar.gz → 2.2.dev3494__tar.gz

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.
Files changed (38) hide show
  1. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/PKG-INFO +1 -1
  2. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/pyproject.toml +1 -1
  3. qmenta_sdk_lib-2.2.dev3494/python/qmenta/sdk/__init__.py +2 -0
  4. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/bids/wrapper.py +9 -5
  5. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/client.py +4 -2
  6. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/communication.py +21 -17
  7. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/context.py +3 -1
  8. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/directory_utils.py +2 -1
  9. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/executor.py +8 -4
  10. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/init.py +10 -6
  11. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/local/client.py +2 -1
  12. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/local/context.py +60 -32
  13. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/local/executor.py +12 -6
  14. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/log_capture.py +13 -7
  15. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/make_entrypoint.py +2 -1
  16. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/inputs.py +2 -1
  17. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/integration_ui.py +64 -12
  18. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/integration_workflow_ui.py +89 -55
  19. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/launch_gui.py +10 -3
  20. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/make_files.py +4 -2
  21. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/outputs.py +8 -2
  22. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/run_test_docker.py +11 -5
  23. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/tool_maker.py +127 -69
  24. qmenta_sdk_lib-2.2.dev3493/python/qmenta/sdk/__init__.py +0 -1
  25. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/__init__.py +0 -0
  26. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/bids/__init__.py +0 -0
  27. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/bids/make_entrypoint.py +0 -0
  28. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/local/__init__.py +0 -0
  29. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/local/parse_settings.py +0 -0
  30. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/__init__.py +0 -0
  31. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/context.py +0 -0
  32. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/file_filter.py +0 -0
  33. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/modalities.py +0 -0
  34. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/templates_tool_maker/Dockerfile_schema +0 -0
  35. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/templates_tool_maker/description_schema +0 -0
  36. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/templates_tool_maker/qmenta.png +0 -0
  37. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/templates_tool_maker/test_tool_schema +0 -0
  38. {qmenta_sdk_lib-2.2.dev3493 → qmenta_sdk_lib-2.2.dev3494}/python/qmenta/sdk/tool_maker/templates_tool_maker/tool_schema +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qmenta-sdk-lib
3
- Version: 2.2.dev3493
3
+ Version: 2.2.dev3494
4
4
  Summary: QMENTA SDK for tool development.
5
5
  Author: QMENTA
6
6
  Maintainer: Marc Ramos
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "qmenta-sdk-lib"
3
- version = "2.2.dev3493"
3
+ version = "2.2.dev3494"
4
4
  description = "QMENTA SDK for tool development."
5
5
  authors = ["QMENTA"]
6
6
  packages = [
@@ -0,0 +1,2 @@
1
+ # This is filled by CI at build time (also used for documentation)
2
+ __version__ = "{version}"
@@ -83,7 +83,8 @@ def generate_file_path(original_name, sub_name, modality_name, cat_dir):
83
83
 
84
84
  def format_input_data(context, subject, session, path):
85
85
  """
86
- Format input data followings the BIDS specification: http://bids.neuroimaging.io/bids_spec.pdf
86
+ Format input data followings the BIDS specification:
87
+ http://bids.neuroimaging.io/bids_spec.pdf
87
88
 
88
89
  :param context: AnalysisContext of the running analysis
89
90
  :param subject: Subject name (from analysis_data)
@@ -97,7 +98,8 @@ def format_input_data(context, subject, session, path):
97
98
 
98
99
  dataset_description = {"Name": "QMENTA_ANALYSIS", "BIDSVersion": "1.1.0"}
99
100
 
100
- # The input container specification must include file filters following the bids_ff_names nomenclature
101
+ # The input container specification must include file filters following
102
+ # the bids_ff_names nomenclature
101
103
  bids_ff_names = {
102
104
  "anat": [
103
105
  "T1w",
@@ -155,9 +157,10 @@ def format_input_data(context, subject, session, path):
155
157
 
156
158
  if os.path.isfile(target_path):
157
159
  logger.warning(
158
- "Multiple files with same name ({}). Only the first will be used".format(
160
+ "Multiple files with same name ({}).".format(
159
161
  target_path
160
- )
162
+ ),
163
+ " Only the first will be used"
161
164
  )
162
165
  break
163
166
 
@@ -211,7 +214,8 @@ def run(context):
211
214
  mkdirs(input_path)
212
215
  mkdirs(output_path)
213
216
 
214
- # Download data from the platform and store following the BIDS specification
217
+ # Download data from the platform and store following
218
+ # the BIDS specification
215
219
  format_input_data(
216
220
  context,
217
221
  subject=analysis_data["patient_secret_name"],
@@ -28,7 +28,8 @@ class ExecClient(object):
28
28
  Parameters
29
29
  ----------
30
30
  user_script_path : str
31
- Should look like 'path.to.module:object', where 'object' should be an importable analysis tool class
31
+ Should look like 'path.to.module:object', where 'object' should be
32
+ an importable analysis tool class
32
33
  or a function taking one 'context' argument.
33
34
  """
34
35
 
@@ -70,7 +71,8 @@ class ExecClient(object):
70
71
  Parameters
71
72
  ----------
72
73
  state : AnalysisState
73
- One of AnalysisState.RUNNING, AnalysisState.COMPLETED, AnalysisState.EXCEPTION or AnalysisState.NO_FILES
74
+ One of AnalysisState.RUNNING, AnalysisState.COMPLETED,
75
+ AnalysisState.EXCEPTION or AnalysisState.NO_FILES
74
76
  kwargs : dict
75
77
  """
76
78
  assert isinstance(
@@ -33,15 +33,17 @@ class CommunicationObject(object):
33
33
  token : str
34
34
  Unique token that authenticates the communication
35
35
  timeout : float or tuple, optional
36
- How many seconds to wait for the server to send data before giving up, as a float, or a
37
- (connect timeout, read timeout) tuple. Defaults to
36
+ How many seconds to wait for the server to send data before giving
37
+ up, as a float, or a (connect timeout, read timeout) tuple.
38
+ Defaults to
38
39
  chunk_size : int
39
40
  Size of chunks in bytes (1MB = 1024KB, 1KB = 1024B)
40
41
  verify : bool, optional
41
42
  Controls whether the server's TLS certificate is verified.
42
43
  Defaults to True.
43
44
  critical: bool, optional
44
- Overrides total_retry seting in requests by making themm fail after the first error if set.
45
+ Overrides total_retry seting in requests by making themm fail
46
+ after the first error if set.
45
47
  """
46
48
  self.timeout = timeout
47
49
  self.chunk_size = chunk_size
@@ -60,7 +62,8 @@ class CommunicationObject(object):
60
62
  def __exit__(self, exc_type, exc_value, traceback):
61
63
  ret = self.send_request("logout")
62
64
  if not ret["success"]:
63
- # Not being able to logout is a security issue and must be a fatal error
65
+ # Not being able to logout is a security issue and must be a
66
+ # fatal error
64
67
  raise RuntimeError("Unable to logout")
65
68
 
66
69
  def send_request(
@@ -82,15 +85,15 @@ class CommunicationObject(object):
82
85
  Parameters
83
86
  ----------
84
87
  access_point : str, optional
85
- API endpoint. Will be joined with the request URL provided at construction time to create the
86
- full ("absolute") url
88
+ API endpoint. Will be joined with the request URL provided at
89
+ construction time to create the full ("absolute") url
87
90
  req_data : dict or str, optional
88
91
  Request data
89
92
  req_headers : dict, optional
90
93
  Request headers
91
94
  return_json : bool, optional
92
- Whether the response should be a JSON object or a requests.Response instance.
93
- Defaults to True.
95
+ Whether the response should be a JSON object or a requests.
96
+ Response instance. Defaults to True.
94
97
  timeout : float, optional
95
98
  Timeout in seconds for this request.
96
99
  Defaults to the timeout set at construction time.
@@ -100,7 +103,8 @@ class CommunicationObject(object):
100
103
  stream : bool, optional
101
104
  If False, the response content will be immediately downloaded.
102
105
  url : str, optional
103
- When no access_point is provided, a full url must be provided through this argument
106
+ When no access_point is provided, a full url must be provided
107
+ through this argument
104
108
  kwargs : dict
105
109
  Additional arguments to be passed to `requests.Session.post`
106
110
  method: str
@@ -109,8 +113,8 @@ class CommunicationObject(object):
109
113
  Returns
110
114
  -------
111
115
  requests.Response or dict
112
- JSON response encoded in a dictionary if return_json is True (default),
113
- otherwise requests.Response object.
116
+ JSON response encoded in a dictionary if return_json is True
117
+ (default), otherwise requests.Response object.
114
118
  """
115
119
  logger = logging.getLogger(__name__)
116
120
 
@@ -179,8 +183,8 @@ class CommunicationObject(object):
179
183
  Parameters
180
184
  ----------
181
185
  access_point : str
182
- API endpoint. Will be joined with the request URL provided at construction time to create the
183
- full ("absolute") url
186
+ API endpoint. Will be joined with the request URL provided at
187
+ construction time to create the full ("absolute") url
184
188
  files : dict
185
189
  Request files
186
190
  req_data : dict or str, optional
@@ -188,8 +192,8 @@ class CommunicationObject(object):
188
192
  req_headers : dict, optional
189
193
  Request headers
190
194
  return_json : bool, optional
191
- Whether the response should be a JSON object or a requests.Response instance.
192
- Defaults to True.
195
+ Whether the response should be a JSON object or a requests.
196
+ Response instance. Defaults to True.
193
197
  timeout : float, optional
194
198
  Timeout in seconds for this request.
195
199
  Defaults to the timeout set at construction time.
@@ -204,8 +208,8 @@ class CommunicationObject(object):
204
208
  Returns
205
209
  -------
206
210
  requests.Response or dict
207
- JSON response encoded in a dictionary if return_json is True (default),
208
- otherwise requests.Response object.
211
+ JSON response encoded in a dictionary if return_json is True
212
+ (default), otherwise requests.Response object.
209
213
  """
210
214
  logger = logging.getLogger(__name__)
211
215
 
@@ -973,7 +973,9 @@ class AnalysisContext:
973
973
  "replace_flag": replace.value,
974
974
  "tags": ",".join(tags),
975
975
  "file_info": json.dumps(file_info),
976
- "file_format": file_format or self.__detect_file_format(source_file_path),
976
+ "file_format": file_format or self.__detect_file_format(
977
+ source_file_path
978
+ ),
977
979
  "protocol": str(
978
980
  protocol or file_name.split(".")[0]
979
981
  if "." in file_name
@@ -4,7 +4,8 @@ import tempfile
4
4
 
5
5
  class TemporaryDirectory:
6
6
  """
7
- Context manager which creates a temporary directory and removes it automatically.
7
+ Context manager which creates a temporary directory and removes it
8
+ automatically.
8
9
  """
9
10
 
10
11
  def __init__(self):
@@ -63,7 +63,8 @@ def parse_args():
63
63
  argp.add_argument(
64
64
  "--tool-path",
65
65
  required=True,
66
- help="Path to the Python tool (package.module:function) to be executed",
66
+ help="Path to the Python tool (package.module:function)"
67
+ "to be executed",
67
68
  )
68
69
 
69
70
  # verbosity
@@ -76,8 +77,10 @@ def parse_args():
76
77
  "--chunk-size",
77
78
  type=str,
78
79
  default=default_chunk_size,
79
- help="Size of each chunk in download/upload operations, expressed in a human readable data size. "
80
- "(e.g. 256 --> 256 bytes ; 512B --> 512 bytes ; 1MiB --> 1048576 bytes; 1MB --> 1000000",
80
+ help="Size of each chunk in download/upload operations,"
81
+ "expressed in a human readable data size. "
82
+ "(e.g. 256 --> 256 bytes ; 512B --> 512 bytes ;"
83
+ "1MiB --> 1048576 bytes; 1MB --> 1000000",
81
84
  )
82
85
 
83
86
  # only for testing purposes
@@ -95,7 +98,8 @@ def parse_args():
95
98
  nargs="?",
96
99
  const=True,
97
100
  default=False,
98
- help="Ignore requests total_retry number and fail after each first errror",
101
+ help="Ignore requests total_retry number and fail after each first"
102
+ "error",
99
103
  )
100
104
 
101
105
  # metadata
@@ -52,9 +52,12 @@ def run(context):
52
52
  for file_handler in input_files:
53
53
  file_handler.download('/root/') # Keeping the original names
54
54
 
55
- # Call the MATLAB helper script with the path of the MATLAB runtime installation
56
- # Make sure your script finalizes. Otherwise this call will be waiting forever
57
- # Alternatively, you can always implement a timeout (e.g. with subprocess)
55
+ # Call the MATLAB helper script with the path of the MATLAB runtime
56
+ # installation.
57
+ # Make sure your script finalizes. Otherwise this call will be waiting
58
+ # forever.
59
+ # Alternatively, you can always implement a timeout
60
+ # (e.g. with subprocess)
58
61
 
59
62
  # os.system('/root/MATLAB_run_script.sh /opt/mcr/v92')
60
63
 
@@ -68,8 +71,8 @@ def run(context):
68
71
  analysis_data = context.fetch_analysis_data()
69
72
 
70
73
  # Get the complete list of input file handlers
71
- input_files = context.get_files('input') # You can add fitlers (modality, tags...)
72
-
74
+ # You can add fitlers (modality, tags...)
75
+ input_files = context.get_files('input')
73
76
  # Download them
74
77
  for file_handler in input_files:
75
78
  file_handler.download('/root/')
@@ -78,7 +81,8 @@ def run(context):
78
81
  # ...
79
82
 
80
83
  # And upload the results
81
- # context.upload_file(path, path_in_output) # You can add filters (modality, tags...)
84
+ # context.upload_file(path, path_in_output)
85
+ # # You can add filters (modality, tags...)
82
86
  """
83
87
 
84
88
  mrinfo_mrtrix_default_tool = """
@@ -16,7 +16,8 @@ class LocalExecClient(ExecClient): # Override main execution client
16
16
  Parameters
17
17
  ----------
18
18
  state : AnalysisState
19
- One of AnalysisState.RUNNING, AnalysisState.COMPLETED, AnalysisState.EXCEPTION or AnalysisState.NO_FILES
19
+ One of AnalysisState.RUNNING, AnalysisState.COMPLETED,
20
+ AnalysisState.EXCEPTION or AnalysisState.NO_FILES
20
21
  kwargs : dict
21
22
  """
22
23
  logging.getLogger(__name__).info(
@@ -30,7 +30,8 @@ class LocalAnalysisContext:
30
30
 
31
31
  def __init__(self, settings, src_folder, out_folder, res_folder):
32
32
  """
33
- Context object that interfaces with the QMENTA platform. Should not be created directly.
33
+ Context object that interfaces with the QMENTA platform.
34
+ Should not be created directly.
34
35
  """
35
36
 
36
37
  self.__settings = settings
@@ -45,14 +46,17 @@ class LocalAnalysisContext:
45
46
  Returns
46
47
  -------
47
48
  dict
48
- Dictionary that contains important information about the current analysis, such as:
49
+ Dictionary that contains important information about
50
+ the current analysis, such as:
49
51
  * state (str) : State of the analysis
50
52
  * name (str) : Name of the analysis
51
53
  * script_name (str) : Name of the script
52
- * user_id (str) : Username of the user that started the analysis
54
+ * user_id (str) : Username of the user that started
55
+ the analysis
53
56
  * patient_secret_name (str) : Name of the subject
54
57
  * ssid (str) : Timepoint identifier
55
- * settings (dict) : Settings dictionary. See documentation in method `get_settings`
58
+ * settings (dict) : Settings dictionary.
59
+ See documentation in method `get_settings`
56
60
  * tags (list) : List of tags
57
61
  * version (str) : Tool version
58
62
  """
@@ -83,11 +87,13 @@ class LocalAnalysisContext:
83
87
  status : QCStatus
84
88
  QCStatus.PASS or QCStatus.FAIL
85
89
  comments : str, optional
86
- Additional comments explaining why the QC status has been set to pass or fail.
90
+ Additional comments explaining why
91
+ the QC status has been set to pass or fail.
87
92
  entity : QCEntity, optional
88
93
  QCEntity.ANALYSIS or QCEntity.SESSION
89
94
  input_id : str, optional
90
- The id of the session in the settings definition when entity is QCEntity.SESSION
95
+ The id of the session in the settings definition when
96
+ entity is QCEntity.SESSION
91
97
  """
92
98
  logger = logging.getLogger(__name__)
93
99
 
@@ -148,7 +154,8 @@ class LocalAnalysisContext:
148
154
  Parameters
149
155
  ----------
150
156
  value : int, optional
151
- Number between 0 and 100 indicating the current status of the execution
157
+ Number between 0 and 100 indicating the current status of the
158
+ execution
152
159
  message : str, optional
153
160
  Progress message.
154
161
  """
@@ -164,12 +171,14 @@ class LocalAnalysisContext:
164
171
  value = int(value) # Cast to int to avoid float/string problems
165
172
  if value > 100:
166
173
  logger.warning(
167
- "The progress value should be between 0 and 100 (using 100 instead)"
174
+ "The progress value should be between 0 and 100"
175
+ "(using 100 instead)"
168
176
  )
169
177
  value = 100
170
178
  elif value < 0:
171
179
  logger.warning(
172
- "The progress value should be between 0 and 100 (using 0 instead)"
180
+ "The progress value should be between 0 and 100"
181
+ "(using 0 instead)"
173
182
  )
174
183
  value = 0
175
184
 
@@ -196,8 +205,8 @@ class LocalAnalysisContext:
196
205
  subject_container_id=None,
197
206
  ):
198
207
  """
199
- Returns the files in the input container specified by `input_id` that match the modality, tags
200
- and regular expression, if any.
208
+ Returns the files in the input container specified by `input_id` that
209
+ match the modality, tags and regular expression, if any.
201
210
 
202
211
  Parameters
203
212
  ----------
@@ -207,12 +216,12 @@ class LocalAnalysisContext:
207
216
  Optional modality, will allow any modalities if None given.
208
217
  Default is None.
209
218
  tags : set, optional
210
- Optional set of tags, will allow any tags if None given, and will match any set of tags (including
211
- the empty set) otherwise.
219
+ Optional set of tags, will allow any tags if None given, and will
220
+ match any set of tags (including the empty set) otherwise.
212
221
  Default is None.
213
222
  reg_expression : str, optional
214
- Regular expression to match with the file names in the specified container, will allow any file names
215
- if None given.
223
+ Regular expression to match with the file names in the specified
224
+ container, will allow any file names if None given.
216
225
  Default is None.
217
226
  file_filter_condition_name : str, optional
218
227
  File filter specified in the settings of the tool.
@@ -235,8 +244,11 @@ class LocalAnalysisContext:
235
244
  # Create File
236
245
  for file_description in self.__settings[input_id]:
237
246
  if "path" not in file_description:
238
- msg = 'Cannot find the key "path" for the input container {}'.format(
239
- input_id
247
+ msg = (
248
+ 'Cannot find the key "path" '
249
+ 'for the input container {}'.format(
250
+ input_id
251
+ )
240
252
  )
241
253
  logger.error(msg)
242
254
  raise RuntimeError(msg)
@@ -343,7 +355,8 @@ class LocalAnalysisContext:
343
355
 
344
356
  def download_resource(self, resource_path, destination_path):
345
357
  """
346
- Downloads a file from the user/group tool resources. The resource path can include subdirectories and must
358
+ Downloads a file from the user/group tool resources.
359
+ The resource path can include subdirectories and must
347
360
  be relative:
348
361
  Downloads a resource file to the container.
349
362
 
@@ -389,7 +402,8 @@ class LocalAnalysisContext:
389
402
 
390
403
  def _get_manual_analysis_data(self):
391
404
  """
392
- Returns a dictionary with the manual analysis data generated during the manual step (user interaction)
405
+ Returns a dictionary with the manual analysis data generated during
406
+ the manual step (user interaction)
393
407
 
394
408
  Returns
395
409
  -------
@@ -399,7 +413,8 @@ class LocalAnalysisContext:
399
413
  logger = logging.getLogger(__name__)
400
414
  logger.info("Getting manual analysis data")
401
415
  logger.warning(
402
- "Getting manual analysis data is not supported locally. Skipping..."
416
+ "Getting manual analysis data is not supported locally. "
417
+ "Skipping..."
403
418
  )
404
419
  return {}
405
420
 
@@ -424,7 +439,8 @@ class LocalAnalysisContext:
424
439
  title : str, optional
425
440
  How the metadata field should be presented
426
441
  readonly : bool, optional
427
- Whether the user should be able to edit the value on the platform or not (only by analyses)
442
+ Whether the user should be able to edit the value on the platform
443
+ or not (only by analyses)
428
444
  """
429
445
  logger = logging.getLogger(__name__)
430
446
 
@@ -476,12 +492,14 @@ class LocalAnalysisContext:
476
492
 
477
493
  def _assure_metadata_parameters(self, params):
478
494
  """
479
- Check whether a metadata parameter exists, creating it if not. Not supported for local testing.
495
+ Check whether a metadata parameter exists, creating it if not.
496
+ Not supported for local testing.
480
497
 
481
498
  Parameters
482
499
  ----------
483
500
  params : dict
484
- The definition of the parameter. It may contain "title", "type", "visible", "readonly" or "order".
501
+ The definition of the parameter. It may contain "title", "type",
502
+ "visible", "readonly" or "order".
485
503
  """
486
504
  logger = logging.getLogger(__name__)
487
505
  logger.info("Setting metadata param (ckeck): {}".format(params))
@@ -509,7 +527,8 @@ class LocalAnalysisContext:
509
527
  class LocalFile:
510
528
  def __init__(self, name, input_container_path, modality, tags, file_info):
511
529
  """
512
- Object that represents a file and all its metadata in the platform. Should not be created directly.
530
+ Object that represents a file and all its metadata in the platform.
531
+ Should not be created directly.
513
532
  """
514
533
  self.name = name
515
534
  self.__input_container_path = input_container_path
@@ -543,13 +562,16 @@ class LocalFile:
543
562
 
544
563
  def get_file_info(self):
545
564
  """
546
- Get the file information. The type of information depends on the type of file
547
- (e.g. nifti files include information such as 'Data strides', 'Data type', 'Dimensions' or 'Voxel size').
565
+ Get the file information.
566
+ The type of information depends on the type of file
567
+ (e.g. nifti files include information such as 'Data strides',
568
+ 'Data type', 'Dimensions' or 'Voxel size').
548
569
 
549
570
  Returns
550
571
  -------
551
572
  dict
552
- Dictionary of key-value pairs that depend on the format of the file.
573
+ Dictionary of key-value pairs that depend on the format of
574
+ the file.
553
575
  """
554
576
  return self.__file_info
555
577
 
@@ -579,8 +601,11 @@ class LocalFile:
579
601
  If `get_file_path` is called before the file has been downloaded
580
602
  """
581
603
  if self.__download_path is None:
582
- err_msg = "File {!r} has no path because it has not been downloaded".format(
583
- self.name
604
+ err_msg = (
605
+ "File {!r} has no path because it has".format(
606
+ self.name
607
+ ),
608
+ "not been downloaded"
584
609
  )
585
610
  logging.getLogger(__name__).error(err_msg)
586
611
  raise RuntimeError(err_msg)
@@ -607,14 +632,16 @@ class LocalFile:
607
632
 
608
633
  def download(self, dest_path, unpack=True):
609
634
  """
610
- Downloads a file or the contents of a packed file to to the specified `path`.
635
+ Downloads a file or the contents of a packed file to to the specified
636
+ `path`.
611
637
 
612
638
  Parameters
613
639
  ----------
614
640
  dest_path:
615
641
  Path where the file should be downloaded to.
616
642
  unpack:
617
- Tells the function whether the file should be unpacked to the given folder.
643
+ Tells the function whether the file should be unpacked to the
644
+ given folder.
618
645
 
619
646
  Returns
620
647
  -------
@@ -630,7 +657,8 @@ class LocalFile:
630
657
  logger.debug("Using path {!r}".format(dest_path))
631
658
 
632
659
  if source_file.endswith(".zip") and unpack:
633
- # Download the zip to a temporary directory and unpack its contents to the user dir path
660
+ # Download the zip to a temporary directory and unpack its
661
+ # contents to the user dir path
634
662
  with TemporaryDirectory() as temp_dir:
635
663
  temp_path = os.path.join(temp_dir, source_file)
636
664
  self.__download_file(temp_path)
@@ -12,13 +12,15 @@ from qmenta.sdk.local.parse_settings import parse_tool_settings
12
12
 
13
13
  def parse_args():
14
14
  argp = argparse.ArgumentParser(
15
- description="Local executor for debugging and testing purposes (SDK version {})".format(
15
+ description="Local executor for debugging and testing purposes (SDK "
16
+ "version {})".format(
16
17
  __version__
17
18
  )
18
19
  )
19
20
  argp.add_argument(
20
21
  "settings",
21
- help="JSON file that defines the settings of the tool to be run. Uses same syntax as in platform. "
22
+ help="JSON file that defines the settings of the tool to be run."
23
+ "Uses same syntax as in platform. "
22
24
  "See qmenta_sdk/examples/",
23
25
  )
24
26
  argp.add_argument(
@@ -28,22 +30,26 @@ def parse_args():
28
30
  argp.add_argument(
29
31
  "src_folder",
30
32
  help="Source folder where the inputs of the analysis are stored."
31
- 'That is you "get_files" from this folder, that represents an input container.',
33
+ 'That is you "get_files" from this folder, that represents an input'
34
+ 'container.',
32
35
  )
33
36
  argp.add_argument(
34
37
  "dst_folder",
35
- help="Destination folder where the outputs of the analysis will be stored."
38
+ help="Destination folder where the outputs of the analysis will be"
39
+ "stored."
36
40
  'That is, when you "upload_file", the file is stored in this folder.',
37
41
  )
38
42
  argp.add_argument(
39
43
  "--res-folder",
40
- help="Folder where the different template files required by the analysis are stored.",
44
+ help="Folder where the different template files required by the"
45
+ "analysis are stored.",
41
46
  default=None,
42
47
  )
43
48
  argp.add_argument(
44
49
  "--tool-path",
45
50
  required=True,
46
- help="Path to the Python tool (package.module:function) to be executed",
51
+ help="Path to the Python tool (package.module:function)"
52
+ "to be executed",
47
53
  )
48
54
  argp.add_argument("--log-path", help="Log file")
49
55
  argp.add_argument(
@@ -4,7 +4,8 @@ from contextlib import contextmanager
4
4
 
5
5
  class LogCaptureHandler(logging.Handler):
6
6
  """
7
- Log handler that captures all messages that it handles and exposes them as a list in `log_sequence` attribute.
7
+ Log handler that captures all messages that it handles and exposes them as
8
+ a list in `log_sequence` attribute.
8
9
  """
9
10
 
10
11
  def __init__(self):
@@ -34,30 +35,35 @@ class GlobFilter(logging.Filter):
34
35
  @contextmanager
35
36
  def capture_log(logger_name_glob, log_level=logging.INFO):
36
37
  """
37
- Context manager that captures the logs of all loggers that satisfy `logger_name_glob`
38
- with associated severity greater or equal than `log_level`.
38
+ Context manager that captures the logs of all loggers that satisfy
39
+ `logger_name_glob` with associated severity greater or equal than
40
+ `log_level`.
39
41
 
40
42
  Parameters
41
43
  ----------
42
44
  logger_name_glob : str
43
45
  Glob expression that specified the loggers should be captured.
44
46
  log_level : int, optional
45
- Minimum severity level to be captured, included. Default is logging.INFO.
47
+ Minimum severity level to be captured, included.
48
+ Default is logging.INFO.
46
49
 
47
50
  Returns
48
51
  -------
49
52
  LogCaptureHandler
50
- Handler that exposes the `log_sequence` attribute, which consists of a list of captured messages.
53
+ Handler that exposes the `log_sequence` attribute, which consists of a
54
+ list of captured messages.
51
55
 
52
56
  Examples
53
57
  --------
54
58
  >>> logger = logging.getLogger('package.module.method')
55
- >>> with capture_log('package.module.*', log_level=logging.WARNING) as captured_logs:
59
+ >>> with capture_log('package.module.*', log_level=logging.WARNING)
60
+ as captured_logs:
56
61
  ... logger.info("This info message won't be captured")
57
62
  ... logger.warning("This warning message will be captured")
58
63
  ... logger.critical("This critical message will be also captured")
59
64
  ... print([record.msg for record in captured_logs.log_sequence])
60
- ['This warning message will be captured', 'This critical message will be also captured']
65
+ ['This warning message will be captured', 'This critical message will be
66
+ also captured']
61
67
  """
62
68
  # Set up the handler, filter and log level
63
69
  root_logger = logging.getLogger()
@@ -8,7 +8,8 @@ export PYTHONPATH="${{PYTHONPATH:+$PYTHONPATH:}}{tool_path}"
8
8
  # ...
9
9
 
10
10
  # Source the export_paths.txt file if exist to load the system paths.
11
- # This file is created in the ci when performing a multi-level build of the docker images
11
+ # This file is created in the ci when performing a multi-level build
12
+ # of the docker images
12
13
 
13
14
  if [ -f "/root/export_paths.txt" ]; then
14
15
  source /root/export_paths.txt
@@ -209,7 +209,8 @@ class ContainerHandler(Input):
209
209
  analysis_dir, "input_folder", self.id, folder_to_save_file
210
210
  )
211
211
 
212
- # This takes into account the path of the file in the input container in the platform
212
+ # This takes into account the path of the file in the input
213
+ # container in the platform
213
214
  logger.info(f"Saving to path: {os.path.dirname(fpath)}.")
214
215
 
215
216
  # in local testing, we need to create the directory