qmenta-sdk-lib 2.0.1.dev3469__tar.gz → 2.0.1.dev3470__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.
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/PKG-INFO +1 -1
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/pyproject.toml +1 -1
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/context.py +104 -163
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/context.py +48 -125
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/__init__.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/__init__.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/bids/__init__.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/bids/make_entrypoint.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/bids/wrapper.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/client.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/communication.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/directory_utils.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/executor.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/init.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/__init__.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/client.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/executor.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/parse_settings.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/log_capture.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/make_entrypoint.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/__init__.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/context.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/file_filter.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/inputs.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/integration_ui.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/integration_workflow_ui.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/launch_gui.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/make_files.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/modalities.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/outputs.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/run_test_docker.py +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/templates_tool_maker/Dockerfile_schema +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/templates_tool_maker/description_schema +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/templates_tool_maker/qmenta.png +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/templates_tool_maker/test_tool_schema +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/templates_tool_maker/tool_schema +0 -0
- {qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/tool_maker.py +0 -0
|
@@ -51,8 +51,7 @@ class AnalysisContext:
|
|
|
51
51
|
|
|
52
52
|
def __init__(self, analysis_id, comm):
|
|
53
53
|
"""
|
|
54
|
-
Context object that interfaces with the QMENTA platform. Should not be
|
|
55
|
-
created directly.
|
|
54
|
+
Context object that interfaces with the QMENTA platform. Should not be created directly.
|
|
56
55
|
"""
|
|
57
56
|
self.analysis_id = analysis_id
|
|
58
57
|
self.__comm = comm
|
|
@@ -74,19 +73,15 @@ class AnalysisContext:
|
|
|
74
73
|
Returns
|
|
75
74
|
-------
|
|
76
75
|
dict
|
|
77
|
-
Dictionary that contains important information about the
|
|
78
|
-
current analysis, such as:
|
|
76
|
+
Dictionary that contains important information about the current analysis, such as:
|
|
79
77
|
* state (str) : State of the analysis
|
|
80
78
|
* name (str) : Name of the analysis
|
|
81
79
|
* script_name (str) : Name of the script
|
|
82
|
-
* analysis_id (str) : A unique identifier for the
|
|
83
|
-
|
|
84
|
-
* user_id (str) : Username of the user that started
|
|
85
|
-
the analysis
|
|
80
|
+
* analysis_id (str) : A unique identifier for the current analysis
|
|
81
|
+
* user_id (str) : Username of the user that started the analysis
|
|
86
82
|
* patient_secret_name (str) : Name of the subject
|
|
87
83
|
* ssid (str) : Timepoint identifier
|
|
88
|
-
* settings (dict) : Settings dictionary. See documentation in
|
|
89
|
-
method `get_settings`
|
|
84
|
+
* settings (dict) : Settings dictionary. See documentation in method `get_settings`
|
|
90
85
|
* tags (list) : List of tags
|
|
91
86
|
* version (str) : Tool version
|
|
92
87
|
"""
|
|
@@ -110,17 +105,14 @@ class AnalysisContext:
|
|
|
110
105
|
Returns
|
|
111
106
|
-------
|
|
112
107
|
dict
|
|
113
|
-
Dictionary that contains important information about the current
|
|
114
|
-
analysis, such as:
|
|
108
|
+
Dictionary that contains important information about the current analysis, such as:
|
|
115
109
|
* state (str) : State of the analysis
|
|
116
110
|
* name (str) : Name of the analysis
|
|
117
111
|
* script_name (str) : Name of the script
|
|
118
|
-
* user_id (str) : Username of the user that started the
|
|
119
|
-
analysis
|
|
112
|
+
* user_id (str) : Username of the user that started the analysis
|
|
120
113
|
* patient_secret_name (str) : Name of the subject
|
|
121
114
|
* ssid (str) : Timepoint identifier
|
|
122
|
-
* settings (dict) : Settings dictionary. See documentation in
|
|
123
|
-
method `get_settings`
|
|
115
|
+
* settings (dict) : Settings dictionary. See documentation in method `get_settings`
|
|
124
116
|
* tags (list) : List of tags
|
|
125
117
|
* version (str) : Tool version
|
|
126
118
|
"""
|
|
@@ -162,8 +154,7 @@ class AnalysisContext:
|
|
|
162
154
|
|
|
163
155
|
def get_communication_object(self):
|
|
164
156
|
"""
|
|
165
|
-
Return the communication object used for communication
|
|
166
|
-
with the platform
|
|
157
|
+
Return the communication object used for communication with the platform
|
|
167
158
|
|
|
168
159
|
Returns
|
|
169
160
|
-------
|
|
@@ -187,13 +178,11 @@ class AnalysisContext:
|
|
|
187
178
|
status : QCStatus
|
|
188
179
|
QCStatus.PASS or QCStatus.FAIL
|
|
189
180
|
comments : str, optional
|
|
190
|
-
Additional comments explaining why the QC status has been
|
|
191
|
-
set to pass or fail.
|
|
181
|
+
Additional comments explaining why the QC status has been set to pass or fail.
|
|
192
182
|
entity : QCEntity, optional
|
|
193
183
|
QCEntity.ANALYSIS or QCEntity.SESSION
|
|
194
184
|
input_id : str, optional
|
|
195
|
-
The id of the session in the settings definition when
|
|
196
|
-
entity is QCEntity.SESSION
|
|
185
|
+
The id of the session in the settings definition when entity is QCEntity.SESSION
|
|
197
186
|
"""
|
|
198
187
|
if entity == self.QCEntity.ANALYSIS:
|
|
199
188
|
item_id = self.analysis_id
|
|
@@ -243,8 +232,7 @@ class AnalysisContext:
|
|
|
243
232
|
"patient_manager/get_patient_list",
|
|
244
233
|
req_headers={"X-Range": "items=0-9999"},
|
|
245
234
|
req_data={
|
|
246
|
-
"pars_patient_secret_name": "string;"
|
|
247
|
-
f"{self.analysis_data['patient_secret_name']}"
|
|
235
|
+
"pars_patient_secret_name": f"string;{self.analysis_data['patient_secret_name']}"
|
|
248
236
|
},
|
|
249
237
|
)
|
|
250
238
|
self.logger.info(data_sessions[0])
|
|
@@ -361,8 +349,7 @@ class AnalysisContext:
|
|
|
361
349
|
Parameters
|
|
362
350
|
----------
|
|
363
351
|
value : int, optional
|
|
364
|
-
Number between 0 and 100 indicating the current status of the
|
|
365
|
-
execution
|
|
352
|
+
Number between 0 and 100 indicating the current status of the execution
|
|
366
353
|
message : str, optional
|
|
367
354
|
Progress message.
|
|
368
355
|
"""
|
|
@@ -379,14 +366,12 @@ class AnalysisContext:
|
|
|
379
366
|
value = int(value) # Cast to int to avoid float/string problems
|
|
380
367
|
if value > 100:
|
|
381
368
|
self.logger.warning(
|
|
382
|
-
"The progress value should be between 0 and 100 "
|
|
383
|
-
"(using 100 instead)"
|
|
369
|
+
"The progress value should be between 0 and 100 (using 100 instead)"
|
|
384
370
|
)
|
|
385
371
|
value = 100
|
|
386
372
|
elif value < 0:
|
|
387
373
|
self.logger.warning(
|
|
388
|
-
"The progress value should be between 0 and 100 "
|
|
389
|
-
"(using 0 instead)"
|
|
374
|
+
"The progress value should be between 0 and 100 (using 0 instead)"
|
|
390
375
|
)
|
|
391
376
|
value = 0
|
|
392
377
|
data_to_send["value"] = value
|
|
@@ -406,10 +391,8 @@ class AnalysisContext:
|
|
|
406
391
|
Returns
|
|
407
392
|
-------
|
|
408
393
|
dict
|
|
409
|
-
Settings for the current analysis. This includes all the
|
|
410
|
-
|
|
411
|
-
(checkboxes, input fields, etc.) and can be accessed using their
|
|
412
|
-
identifier.
|
|
394
|
+
Settings for the current analysis. This includes all the parameters defined in the tool specification
|
|
395
|
+
(checkboxes, input fields, etc.) and can be accessed using their identifier.
|
|
413
396
|
"""
|
|
414
397
|
return self.analysis_data["settings"]
|
|
415
398
|
|
|
@@ -421,13 +404,10 @@ class AnalysisContext:
|
|
|
421
404
|
reg_expression=None,
|
|
422
405
|
file_filter_condition_name=None,
|
|
423
406
|
subject_container_id=None,
|
|
424
|
-
unpack=True,
|
|
425
407
|
):
|
|
426
408
|
"""
|
|
427
|
-
Returns the files in the input container specified by
|
|
428
|
-
|
|
429
|
-
and regular expression, if any. (X)OR that are selected by
|
|
430
|
-
the file filter condition
|
|
409
|
+
Returns the files in the input container specified by `input_id` that match the modality, tags
|
|
410
|
+
and regular expression, if any. (X)OR that are selected by the file filter condition
|
|
431
411
|
defined in the tool settings.
|
|
432
412
|
|
|
433
413
|
Parameters
|
|
@@ -438,47 +418,38 @@ class AnalysisContext:
|
|
|
438
418
|
Optional modality, will allow any modalities if None given.
|
|
439
419
|
Default is None.
|
|
440
420
|
tags : set, optional
|
|
441
|
-
Optional set of tags, will allow any tags if None given,
|
|
442
|
-
and will match any set of tags (including
|
|
421
|
+
Optional set of tags, will allow any tags if None given, and will match any set of tags (including
|
|
443
422
|
the empty set) otherwise.
|
|
444
423
|
Default is None.
|
|
445
424
|
reg_expression : str, optional
|
|
446
|
-
Regular expression to match with the file names in the specified
|
|
447
|
-
container, will allow any file names
|
|
425
|
+
Regular expression to match with the file names in the specified container, will allow any file names
|
|
448
426
|
if None given.
|
|
449
427
|
Default is None.
|
|
450
428
|
file_filter_condition_name : str, optional
|
|
451
429
|
File filter specified in the settings of the tool.
|
|
452
430
|
Default is None.
|
|
453
431
|
subject_container_id : str, optional
|
|
454
|
-
unpack: bool, optional
|
|
455
432
|
|
|
456
433
|
Examples
|
|
457
434
|
--------
|
|
458
435
|
|
|
459
|
-
Get all files that passed c_TEST (including any selection
|
|
460
|
-
the user may have done using the GUI)
|
|
436
|
+
Get all files that passed c_TEST (including any selection the user may have done using the GUI)
|
|
461
437
|
|
|
462
438
|
>>> context.get_files('input', file_filter_condition_name='c_TEST')
|
|
463
439
|
|
|
464
440
|
Get all files that passed c_TEST and have no tags
|
|
465
441
|
|
|
466
|
-
>>> context.get_files('input', file_fitler_condition_name='c_TEST',
|
|
467
|
-
tags=set()
|
|
442
|
+
>>> context.get_files('input', file_fitler_condition_name='c_TEST', tags=set()
|
|
468
443
|
|
|
469
|
-
Get all files that passed c_TEST and have the DTI tag in their
|
|
470
|
-
list of tags
|
|
444
|
+
Get all files that passed c_TEST and have the DTI tag in their list of tags
|
|
471
445
|
|
|
472
|
-
>>> context.get_files('input', file_fitler_condition_name='c_TEST',
|
|
473
|
-
tags={'DTI'})
|
|
446
|
+
>>> context.get_files('input', file_fitler_condition_name='c_TEST', tags={'DTI'})
|
|
474
447
|
|
|
475
448
|
Get all files that passed c_TEST whose name match the given regexp
|
|
476
449
|
|
|
477
|
-
>>> context.get_files('input', file_filter_condition_name='c_TEST',
|
|
478
|
-
reg_expression='^some_expression[0-9]')
|
|
450
|
+
>>> context.get_files('input', file_filter_condition_name='c_TEST', reg_expression='^some_expression[0-9]')
|
|
479
451
|
|
|
480
|
-
Alternatively, you can use no file_filter_condition_name to browse
|
|
481
|
-
through the whole input container
|
|
452
|
+
Alternatively, you can use no file_filter_condition_name to browse through the whole input container
|
|
482
453
|
|
|
483
454
|
>>> context.get_files('input')
|
|
484
455
|
|
|
@@ -504,10 +475,7 @@ class AnalysisContext:
|
|
|
504
475
|
)
|
|
505
476
|
|
|
506
477
|
if is_subject_setting and subject_container_id is None:
|
|
507
|
-
msg =
|
|
508
|
-
"must define subject_container_id for subjects with"
|
|
509
|
-
" multiple sessions"
|
|
510
|
-
)
|
|
478
|
+
msg = "must define subject_container_id for subjects with multiple sessions"
|
|
511
479
|
self.logger.error(msg)
|
|
512
480
|
raise Exception(msg)
|
|
513
481
|
|
|
@@ -557,8 +525,7 @@ class AnalysisContext:
|
|
|
557
525
|
]
|
|
558
526
|
|
|
559
527
|
if file_filter_condition_name:
|
|
560
|
-
# Get the files that passed the file_filter and take those that
|
|
561
|
-
# have the required conditions
|
|
528
|
+
# Get the files that passed the file_filter and take those that have the required conditions
|
|
562
529
|
|
|
563
530
|
selected_files = []
|
|
564
531
|
|
|
@@ -568,8 +535,9 @@ class AnalysisContext:
|
|
|
568
535
|
file_filter_condition_name
|
|
569
536
|
]
|
|
570
537
|
except KeyError:
|
|
571
|
-
msg =
|
|
572
|
-
|
|
538
|
+
msg = "File filter condition {} not specified in the container {} settings !".format(
|
|
539
|
+
file_filter_condition_name, input_id
|
|
540
|
+
)
|
|
573
541
|
self.logger.error(msg)
|
|
574
542
|
raise Exception(msg)
|
|
575
543
|
|
|
@@ -607,8 +575,7 @@ class AnalysisContext:
|
|
|
607
575
|
|
|
608
576
|
return selected_files
|
|
609
577
|
else:
|
|
610
|
-
# in case the file filter condition name is not specified then we
|
|
611
|
-
# need to take the other
|
|
578
|
+
# in case the file filter condition name is not specified then we need to take the other
|
|
612
579
|
# concrete search conditions i.e. modality, tags, reg_expression
|
|
613
580
|
|
|
614
581
|
# filter the files according to the filter defined
|
|
@@ -640,8 +607,7 @@ class AnalysisContext:
|
|
|
640
607
|
selected_files = []
|
|
641
608
|
for file_data in container_data["meta"]:
|
|
642
609
|
|
|
643
|
-
# TODO: Here we are assuming that file metadata has a name and a
|
|
644
|
-
# metadata attribute. Need of jsonschema
|
|
610
|
+
# TODO: Here we are assuming that file metadata has a name and a metadata attribute. Need of jsonschema
|
|
645
611
|
|
|
646
612
|
fname, fmetadata, ftags = (
|
|
647
613
|
file_data["name"],
|
|
@@ -685,15 +651,13 @@ class AnalysisContext:
|
|
|
685
651
|
patient_metadata_id=None,
|
|
686
652
|
):
|
|
687
653
|
"""
|
|
688
|
-
Add a new scan session. Only functional for analysis tools of type
|
|
689
|
-
`data`.
|
|
654
|
+
Add a new scan session. Only functional for analysis tools of type `data`.
|
|
690
655
|
|
|
691
656
|
Parameters
|
|
692
657
|
----------
|
|
693
658
|
ssid : int, optional
|
|
694
659
|
date_at_scan : str, optional
|
|
695
|
-
Possible formats: '%d.%m.%Y' / '%Y-%m-%d'.
|
|
696
|
-
Examples: '01.01.2000' / '2000-01-01'
|
|
660
|
+
Possible formats: '%d.%m.%Y' / '%Y-%m-%d'. Examples: '01.01.2000' / '2000-01-01'
|
|
697
661
|
age_at_scan : int, optional
|
|
698
662
|
backup_age : int, optional
|
|
699
663
|
patient_metadata_id : int, optional
|
|
@@ -707,15 +671,13 @@ class AnalysisContext:
|
|
|
707
671
|
patient_secret_name = self.analysis_data["patient_secret_name"]
|
|
708
672
|
except KeyError:
|
|
709
673
|
raise RuntimeError(
|
|
710
|
-
"Patient secret name not available in analysis information. "
|
|
711
|
-
"Check platform failures."
|
|
674
|
+
"Patient secret name not available in analysis information. Check platform failures."
|
|
712
675
|
)
|
|
713
676
|
try:
|
|
714
677
|
md5_original_file = self.get_settings()["md5_original_file"]
|
|
715
678
|
except KeyError:
|
|
716
679
|
raise RuntimeError(
|
|
717
|
-
"MD5 hash not available via analysis settings. "
|
|
718
|
-
"Check platform failures."
|
|
680
|
+
"MD5 hash not available via analysis settings. Check platform failures."
|
|
719
681
|
)
|
|
720
682
|
|
|
721
683
|
data = {
|
|
@@ -770,8 +732,9 @@ class AnalysisContext:
|
|
|
770
732
|
return True
|
|
771
733
|
else:
|
|
772
734
|
raise RuntimeError(
|
|
773
|
-
"Intermediate chunk upload "
|
|
774
|
-
|
|
735
|
+
"Intermediate chunk upload failed: {!r} != {!r}".format(
|
|
736
|
+
response.text, expected_response
|
|
737
|
+
)
|
|
775
738
|
)
|
|
776
739
|
except Exception as e:
|
|
777
740
|
logger.error(
|
|
@@ -850,8 +813,7 @@ class AnalysisContext:
|
|
|
850
813
|
file_info : dict, optional
|
|
851
814
|
File information metadata.
|
|
852
815
|
file_format : str, optional
|
|
853
|
-
Use "dicom" when .zip file with .dcm slices (uploading a "nifti"
|
|
854
|
-
file is automatically recognized as such).
|
|
816
|
+
Use "dicom" when .zip file with .dcm slices (uploading a "nifti" file is automatically recognized as such).
|
|
855
817
|
protocol : str, optional
|
|
856
818
|
container_id : str, optional
|
|
857
819
|
replace : str, optional
|
|
@@ -900,7 +862,7 @@ class AnalysisContext:
|
|
|
900
862
|
) and chunk_retry_count <= self.__max_chunk_retries:
|
|
901
863
|
start_position = chunk_num * self.__comm.chunk_size
|
|
902
864
|
self.logger.debug(
|
|
903
|
-
"Chunk size
|
|
865
|
+
"Chunk size is {}".format(self.__comm.chunk_size)
|
|
904
866
|
)
|
|
905
867
|
end_position = start_position + self.__comm.chunk_size - 1
|
|
906
868
|
bytes_to_send = self.__comm.chunk_size
|
|
@@ -921,8 +883,9 @@ class AnalysisContext:
|
|
|
921
883
|
"Content-Range": bytes_range,
|
|
922
884
|
"Session-ID": str(session_id),
|
|
923
885
|
"Content-Length": str(bytes_to_send),
|
|
924
|
-
"Content-Disposition": "attachment; "
|
|
925
|
-
|
|
886
|
+
"Content-Disposition": "attachment; filename={}".format(
|
|
887
|
+
file_name
|
|
888
|
+
),
|
|
926
889
|
}
|
|
927
890
|
|
|
928
891
|
# If it is the last chunk, define more header fields
|
|
@@ -930,30 +893,35 @@ class AnalysisContext:
|
|
|
930
893
|
chunk_num * self.__comm.chunk_size + bytes_to_send
|
|
931
894
|
)
|
|
932
895
|
if accumulated_bytes == total_bytes:
|
|
933
|
-
last_data = {
|
|
934
|
-
"X-Mint-Analysis-Output": str(self.analysis_id),
|
|
935
|
-
"X-Mint-File-Destination-Path": destination_path,
|
|
936
|
-
"X-Mint-File-Tags": ",".join(tags),
|
|
937
|
-
}
|
|
938
896
|
self.logger.debug("Sending last data chunk")
|
|
939
|
-
req_headers.update(
|
|
897
|
+
req_headers.update(
|
|
898
|
+
{
|
|
899
|
+
"X-Mint-Analysis-Output": str(
|
|
900
|
+
self.analysis_id
|
|
901
|
+
),
|
|
902
|
+
"X-Mint-File-Destination-Path": destination_path,
|
|
903
|
+
"X-Mint-File-Tags": ",".join(tags),
|
|
904
|
+
}
|
|
905
|
+
)
|
|
940
906
|
|
|
941
907
|
# Conditional headers
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
(
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
)
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
908
|
+
if file_info:
|
|
909
|
+
req_headers["X-Mint-File-Info"] = json.dumps(
|
|
910
|
+
file_info
|
|
911
|
+
)
|
|
912
|
+
if file_format:
|
|
913
|
+
req_headers["X-Mint-File-Format"] = str(
|
|
914
|
+
file_format
|
|
915
|
+
)
|
|
916
|
+
if protocol:
|
|
917
|
+
req_headers["X-Mint-Protocol"] = str(protocol)
|
|
918
|
+
if container_id:
|
|
919
|
+
req_headers["X-Mint-Container"] = str(container_id)
|
|
920
|
+
if replace:
|
|
921
|
+
assert isinstance(
|
|
922
|
+
replace, AnalysisContext.ReplaceFlag
|
|
923
|
+
)
|
|
924
|
+
req_headers["X-Mint-Replace-Flag"] = replace.value
|
|
957
925
|
req_headers["X-Requested-With"] = "XMLHttpRequest"
|
|
958
926
|
|
|
959
927
|
# Send data chunk
|
|
@@ -975,8 +943,9 @@ class AnalysisContext:
|
|
|
975
943
|
wait_time = 2 * wait_time
|
|
976
944
|
time.sleep(wait_time)
|
|
977
945
|
|
|
978
|
-
if
|
|
979
|
-
|
|
946
|
+
if (
|
|
947
|
+
data or chunk_retry_count != 0
|
|
948
|
+
): # Restarted when successful upload
|
|
980
949
|
msg = (
|
|
981
950
|
"File {} could not be uploaded to the platform.\n"
|
|
982
951
|
"data - {}\n"
|
|
@@ -1008,9 +977,6 @@ class AnalysisContext:
|
|
|
1008
977
|
),
|
|
1009
978
|
"container_id": container_id,
|
|
1010
979
|
}
|
|
1011
|
-
|
|
1012
|
-
self.logger.info("REQUEST DATA" + str(request_data))
|
|
1013
|
-
|
|
1014
980
|
url_request_response = self.__comm.send_request(
|
|
1015
981
|
"file_manager/get_upload_url", req_data=request_data
|
|
1016
982
|
)
|
|
@@ -1072,16 +1038,13 @@ class AnalysisContext:
|
|
|
1072
1038
|
self.logger.error(msg)
|
|
1073
1039
|
raise RuntimeError(msg)
|
|
1074
1040
|
|
|
1075
|
-
req_data = {
|
|
1076
|
-
"container_id": container_id,
|
|
1077
|
-
"path": destination_path,
|
|
1078
|
-
"md5": md5_hash,
|
|
1079
|
-
}
|
|
1080
|
-
self.logger.info("VERIFY RESPONSE " + str(req_data))
|
|
1081
|
-
|
|
1082
1041
|
verification_response = self.__comm.send_request(
|
|
1083
1042
|
"file_manager/verify_upload_via_url",
|
|
1084
|
-
req_data=
|
|
1043
|
+
req_data={
|
|
1044
|
+
"container_id": container_id,
|
|
1045
|
+
"path": destination_path,
|
|
1046
|
+
"md5": md5_hash,
|
|
1047
|
+
},
|
|
1085
1048
|
)
|
|
1086
1049
|
if not verification_response.get("success", False):
|
|
1087
1050
|
msg = "The upload could not be verified: {}".format(
|
|
@@ -1094,8 +1057,7 @@ class AnalysisContext:
|
|
|
1094
1057
|
|
|
1095
1058
|
def download_resource(self, resource_path, destination_path):
|
|
1096
1059
|
"""
|
|
1097
|
-
Downloads a resource file from the bucket (user/group based resources,
|
|
1098
|
-
or legacy).
|
|
1060
|
+
Downloads a resource file from the bucket (user/group based resources, or legacy).
|
|
1099
1061
|
|
|
1100
1062
|
Parameters
|
|
1101
1063
|
----------
|
|
@@ -1146,8 +1108,7 @@ class AnalysisContext:
|
|
|
1146
1108
|
|
|
1147
1109
|
def _get_manual_analysis_data(self):
|
|
1148
1110
|
"""
|
|
1149
|
-
Returns a dictionary with the manual analysis data generated during
|
|
1150
|
-
the manual step (user interaction)
|
|
1111
|
+
Returns a dictionary with the manual analysis data generated during the manual step (user interaction)
|
|
1151
1112
|
|
|
1152
1113
|
Returns
|
|
1153
1114
|
-------
|
|
@@ -1195,13 +1156,11 @@ class AnalysisContext:
|
|
|
1195
1156
|
title : str, optional
|
|
1196
1157
|
How the metadata field should be presented
|
|
1197
1158
|
readonly : bool, optional
|
|
1198
|
-
Whether the user should be able to edit the value on the platform
|
|
1199
|
-
or not (only by analyses)
|
|
1159
|
+
Whether the user should be able to edit the value on the platform or not (only by analyses)
|
|
1200
1160
|
patient_secret_name : str, optional
|
|
1201
1161
|
Manually select the patient_secret_name
|
|
1202
1162
|
ssid : str, optional
|
|
1203
|
-
Manually select the ssid. This is useful to choose a specific
|
|
1204
|
-
session in a longitudinal analysis.
|
|
1163
|
+
Manually select the ssid. This is useful to choose a specific session in a longitudinal analysis.
|
|
1205
1164
|
"""
|
|
1206
1165
|
|
|
1207
1166
|
if not isinstance(key, str):
|
|
@@ -1213,8 +1172,7 @@ class AnalysisContext:
|
|
|
1213
1172
|
)
|
|
1214
1173
|
if not isinstance(value, (int, list, str, float)):
|
|
1215
1174
|
raise Exception(
|
|
1216
|
-
"Parameter 'value' must be of type 'int', 'list', 'str', "
|
|
1217
|
-
"or 'float'."
|
|
1175
|
+
"Parameter 'value' must be of type 'int', 'list', 'str', or 'float'."
|
|
1218
1176
|
)
|
|
1219
1177
|
|
|
1220
1178
|
if not self.get_metadata_value(key):
|
|
@@ -1283,13 +1241,11 @@ class AnalysisContext:
|
|
|
1283
1241
|
Parameters
|
|
1284
1242
|
----------
|
|
1285
1243
|
key : str, optional
|
|
1286
|
-
The ID of the metadata parameter. If not set, it will return all
|
|
1287
|
-
the metadata for the session.
|
|
1244
|
+
The ID of the metadata parameter. If not set, it will return all the metadata for the session.
|
|
1288
1245
|
patient_secret_name: str, optional
|
|
1289
1246
|
Manually select the patient_secret_name
|
|
1290
1247
|
ssid : str, optional
|
|
1291
|
-
Manually select the ssid. This is useful to choose a specific
|
|
1292
|
-
session in a longitudinal analysis.
|
|
1248
|
+
Manually select the ssid. This is useful to choose a specific session in a longitudinal analysis.
|
|
1293
1249
|
|
|
1294
1250
|
Returns
|
|
1295
1251
|
-------
|
|
@@ -1338,8 +1294,7 @@ class AnalysisContext:
|
|
|
1338
1294
|
Parameters
|
|
1339
1295
|
----------
|
|
1340
1296
|
params : list
|
|
1341
|
-
The definition of the parameter. It may contain "title", "type",
|
|
1342
|
-
"visible", "readonly" or "order".
|
|
1297
|
+
The definition of the parameter. It may contain "title", "type", "visible", "readonly" or "order".
|
|
1343
1298
|
"""
|
|
1344
1299
|
|
|
1345
1300
|
if not isinstance(params, list):
|
|
@@ -1347,10 +1302,7 @@ class AnalysisContext:
|
|
|
1347
1302
|
|
|
1348
1303
|
for data_to_send in params:
|
|
1349
1304
|
if not isinstance(data_to_send, dict):
|
|
1350
|
-
msg =
|
|
1351
|
-
"Format error. Metadata param configuration should be "
|
|
1352
|
-
"stored in a dictionary"
|
|
1353
|
-
)
|
|
1305
|
+
msg = "Format error. Metadata param configuration should be stored in a dictionary"
|
|
1354
1306
|
self.logger.error(msg)
|
|
1355
1307
|
raise TypeError(msg)
|
|
1356
1308
|
|
|
@@ -1428,8 +1380,9 @@ class AnalysisContext:
|
|
|
1428
1380
|
"""
|
|
1429
1381
|
if not isinstance(variables_dict, dict):
|
|
1430
1382
|
self.logger.error(
|
|
1431
|
-
"The output variables are not of type dictionary ! "
|
|
1432
|
-
|
|
1383
|
+
"The output variables are not of type dictionary ! (actual type {})".format(
|
|
1384
|
+
str(type(variables_dict))
|
|
1385
|
+
)
|
|
1433
1386
|
)
|
|
1434
1387
|
raise RuntimeError(
|
|
1435
1388
|
"The output variables are not of type dictionary !"
|
|
@@ -1517,8 +1470,7 @@ class Container:
|
|
|
1517
1470
|
class File:
|
|
1518
1471
|
def __init__(self, container_id, name, metadata, tags, comm):
|
|
1519
1472
|
"""
|
|
1520
|
-
Object that represents a file and all its metadata in the platform.
|
|
1521
|
-
Should not be created directly.
|
|
1473
|
+
Object that represents a file and all its metadata in the platform. Should not be created directly.
|
|
1522
1474
|
"""
|
|
1523
1475
|
self.__comm = comm
|
|
1524
1476
|
self.__container_id = container_id
|
|
@@ -1552,16 +1504,13 @@ class File:
|
|
|
1552
1504
|
|
|
1553
1505
|
def get_file_info(self):
|
|
1554
1506
|
"""
|
|
1555
|
-
Get the file information. The type of information depends on the
|
|
1556
|
-
type
|
|
1557
|
-
(e.g. nifti files include information such as 'Data strides',
|
|
1558
|
-
'Data type', 'Dimensions' or 'Voxel size').
|
|
1507
|
+
Get the file information. The type of information depends on the type of file
|
|
1508
|
+
(e.g. nifti files include information such as 'Data strides', 'Data type', 'Dimensions' or 'Voxel size').
|
|
1559
1509
|
|
|
1560
1510
|
Returns
|
|
1561
1511
|
-------
|
|
1562
1512
|
dict
|
|
1563
|
-
Dictionary of key-value pairs that depend on the format of the
|
|
1564
|
-
file.
|
|
1513
|
+
Dictionary of key-value pairs that depend on the format of the file.
|
|
1565
1514
|
"""
|
|
1566
1515
|
return self.__metadata.get("info", {})
|
|
1567
1516
|
|
|
@@ -1591,9 +1540,8 @@ class File:
|
|
|
1591
1540
|
If `get_file_path` is called before the file has been downloaded
|
|
1592
1541
|
"""
|
|
1593
1542
|
if self.__download_path is None:
|
|
1594
|
-
err_msg = (
|
|
1595
|
-
|
|
1596
|
-
" downloaded".format(self.name)
|
|
1543
|
+
err_msg = "File {!r} has no path because it has not been downloaded".format(
|
|
1544
|
+
self.name
|
|
1597
1545
|
)
|
|
1598
1546
|
self.logger.error(err_msg)
|
|
1599
1547
|
raise RuntimeError(err_msg)
|
|
@@ -1651,8 +1599,7 @@ class File:
|
|
|
1651
1599
|
|
|
1652
1600
|
os.makedirs(os.path.dirname(destination_file_path), exist_ok=True)
|
|
1653
1601
|
with open(destination_file_path, "wb") as fp:
|
|
1654
|
-
# For Google Cloud Bucket, performance is at its best at 1 MB or
|
|
1655
|
-
# larger chunks.
|
|
1602
|
+
# For Google Cloud Bucket, performance is at its best at 1 MB or larger chunks.
|
|
1656
1603
|
for chunk in download_response.iter_content(
|
|
1657
1604
|
chunk_size=self.__comm.chunk_size
|
|
1658
1605
|
): # Use 10 MB chunk
|
|
@@ -1667,16 +1614,14 @@ class File:
|
|
|
1667
1614
|
|
|
1668
1615
|
def download(self, dest_path, unpack=True):
|
|
1669
1616
|
"""
|
|
1670
|
-
Downloads a file or the contents of a packed file to to the
|
|
1671
|
-
specified `path`.
|
|
1617
|
+
Downloads a file or the contents of a packed file to to the specified `path`.
|
|
1672
1618
|
|
|
1673
1619
|
Parameters
|
|
1674
1620
|
----------
|
|
1675
1621
|
dest_path:
|
|
1676
1622
|
Path where the file should be downloaded to.
|
|
1677
1623
|
unpack:
|
|
1678
|
-
Tells the function whether the file should be unpacked to the
|
|
1679
|
-
given folder.
|
|
1624
|
+
Tells the function whether the file should be unpacked to the given folder.
|
|
1680
1625
|
|
|
1681
1626
|
Returns
|
|
1682
1627
|
-------
|
|
@@ -1691,16 +1636,13 @@ class File:
|
|
|
1691
1636
|
self.logger.debug("Using path {!r}".format(dest_path))
|
|
1692
1637
|
|
|
1693
1638
|
if source_file.endswith(".zip") and unpack:
|
|
1694
|
-
# Download the zip to a temporary directory and unpack its
|
|
1695
|
-
# contents to the user dir path
|
|
1639
|
+
# Download the zip to a temporary directory and unpack its contents to the user dir path
|
|
1696
1640
|
with TemporaryDirectory() as temp_dir:
|
|
1697
1641
|
temp_path = os.path.join(temp_dir, source_file)
|
|
1698
1642
|
self.__download_file(temp_path)
|
|
1699
|
-
|
|
1700
1643
|
with zipfile.ZipFile(temp_path, "r") as zip_ref:
|
|
1701
1644
|
# file_list = zip_ref.namelist()
|
|
1702
|
-
# self.logger.info("Decompressing {!r} to
|
|
1703
|
-
# {!r}".format(file_list, dest_path))
|
|
1645
|
+
# self.logger.info("Decompressing {!r} to {!r}".format(file_list, dest_path))
|
|
1704
1646
|
os.makedirs(dest_path, exist_ok=True)
|
|
1705
1647
|
zip_ref.extractall(path=dest_path)
|
|
1706
1648
|
|
|
@@ -1727,8 +1669,7 @@ def _should_include_file(
|
|
|
1727
1669
|
search_tags,
|
|
1728
1670
|
search_reg_expression,
|
|
1729
1671
|
):
|
|
1730
|
-
# Checks if file should be selected or not according to the
|
|
1731
|
-
# specified selectors.
|
|
1672
|
+
# Checks if file should be selected or not according to the specified selectors.
|
|
1732
1673
|
|
|
1733
1674
|
assert fname
|
|
1734
1675
|
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/context.py
RENAMED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/python
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
1
|
import logging
|
|
4
2
|
import os
|
|
5
3
|
import shutil
|
|
@@ -12,7 +10,6 @@ from qmenta.sdk.directory_utils import TemporaryDirectory
|
|
|
12
10
|
|
|
13
11
|
|
|
14
12
|
class LocalAnalysisContext:
|
|
15
|
-
|
|
16
13
|
class QCEntity(Enum):
|
|
17
14
|
"""
|
|
18
15
|
Enum with the following options:
|
|
@@ -31,16 +28,9 @@ class LocalAnalysisContext:
|
|
|
31
28
|
PASS = "pass"
|
|
32
29
|
FAIL = "fail"
|
|
33
30
|
|
|
34
|
-
def __init__(
|
|
35
|
-
self,
|
|
36
|
-
settings,
|
|
37
|
-
src_folder,
|
|
38
|
-
out_folder,
|
|
39
|
-
res_folder,
|
|
40
|
-
):
|
|
31
|
+
def __init__(self, settings, src_folder, out_folder, res_folder):
|
|
41
32
|
"""
|
|
42
|
-
Context object that interfaces with the QMENTA platform. Should not
|
|
43
|
-
be created directly.
|
|
33
|
+
Context object that interfaces with the QMENTA platform. Should not be created directly.
|
|
44
34
|
"""
|
|
45
35
|
|
|
46
36
|
self.__settings = settings
|
|
@@ -55,21 +45,17 @@ class LocalAnalysisContext:
|
|
|
55
45
|
Returns
|
|
56
46
|
-------
|
|
57
47
|
dict
|
|
58
|
-
Dictionary that contains important information about the current
|
|
59
|
-
analysis, such as:
|
|
48
|
+
Dictionary that contains important information about the current analysis, such as:
|
|
60
49
|
* state (str) : State of the analysis
|
|
61
50
|
* name (str) : Name of the analysis
|
|
62
51
|
* script_name (str) : Name of the script
|
|
63
|
-
* user_id (str) : Username of the user that started the
|
|
64
|
-
analysis
|
|
52
|
+
* user_id (str) : Username of the user that started the analysis
|
|
65
53
|
* patient_secret_name (str) : Name of the subject
|
|
66
54
|
* ssid (str) : Timepoint identifier
|
|
67
|
-
* settings (dict) : Settings dictionary. See documentation in
|
|
68
|
-
method `get_settings`
|
|
55
|
+
* settings (dict) : Settings dictionary. See documentation in method `get_settings`
|
|
69
56
|
* tags (list) : List of tags
|
|
70
57
|
* version (str) : Tool version
|
|
71
58
|
"""
|
|
72
|
-
|
|
73
59
|
return {
|
|
74
60
|
"state": "local_running",
|
|
75
61
|
"name": "local",
|
|
@@ -97,15 +83,12 @@ class LocalAnalysisContext:
|
|
|
97
83
|
status : QCStatus
|
|
98
84
|
QCStatus.PASS or QCStatus.FAIL
|
|
99
85
|
comments : str, optional
|
|
100
|
-
Additional comments explaining why the QC status has been set to
|
|
101
|
-
pass or fail.
|
|
86
|
+
Additional comments explaining why the QC status has been set to pass or fail.
|
|
102
87
|
entity : QCEntity, optional
|
|
103
88
|
QCEntity.ANALYSIS or QCEntity.SESSION
|
|
104
89
|
input_id : str, optional
|
|
105
|
-
The id of the session in the settings definition when entity is
|
|
106
|
-
QCEntity.SESSION
|
|
90
|
+
The id of the session in the settings definition when entity is QCEntity.SESSION
|
|
107
91
|
"""
|
|
108
|
-
|
|
109
92
|
logger = logging.getLogger(__name__)
|
|
110
93
|
|
|
111
94
|
logger.info("Setting QC status to {}: {}".format(status, comments))
|
|
@@ -115,7 +98,6 @@ class LocalAnalysisContext:
|
|
|
115
98
|
Changes the analysis or session QC status.
|
|
116
99
|
|
|
117
100
|
"""
|
|
118
|
-
|
|
119
101
|
logger = logging.getLogger(__name__)
|
|
120
102
|
|
|
121
103
|
logger.info("Getting QC status")
|
|
@@ -129,17 +111,17 @@ class LocalAnalysisContext:
|
|
|
129
111
|
path : str
|
|
130
112
|
The location where to store the requirements.r
|
|
131
113
|
"""
|
|
132
|
-
|
|
133
114
|
logger = logging.getLogger(__name__)
|
|
134
115
|
|
|
135
116
|
if os.path.exists(path):
|
|
136
117
|
raise RuntimeError(
|
|
137
|
-
"Cannot download session qa because {}"
|
|
138
|
-
|
|
118
|
+
"Cannot download session qa because {} already exists!".format(
|
|
119
|
+
path
|
|
120
|
+
)
|
|
139
121
|
)
|
|
140
122
|
|
|
141
123
|
logger.info(
|
|
142
|
-
"Session QA requirements not supported locally.
|
|
124
|
+
"Session QA requirements not supported locally. Skipping..."
|
|
143
125
|
)
|
|
144
126
|
|
|
145
127
|
def upload_session_qa_report(self, input_id, path):
|
|
@@ -153,10 +135,9 @@ class LocalAnalysisContext:
|
|
|
153
135
|
path : str
|
|
154
136
|
The json file with the QA status for all files and rules
|
|
155
137
|
"""
|
|
156
|
-
|
|
157
138
|
logger = logging.getLogger(__name__)
|
|
158
139
|
logger.info(
|
|
159
|
-
"Session QA requirements not supported locally.
|
|
140
|
+
"Session QA requirements not supported locally. Skipping..."
|
|
160
141
|
)
|
|
161
142
|
|
|
162
143
|
@staticmethod
|
|
@@ -167,17 +148,15 @@ class LocalAnalysisContext:
|
|
|
167
148
|
Parameters
|
|
168
149
|
----------
|
|
169
150
|
value : int, optional
|
|
170
|
-
Number between 0 and 100 indicating the current status of
|
|
171
|
-
the execution
|
|
151
|
+
Number between 0 and 100 indicating the current status of the execution
|
|
172
152
|
message : str, optional
|
|
173
153
|
Progress message.
|
|
174
154
|
"""
|
|
175
|
-
|
|
176
155
|
logger = logging.getLogger(__name__)
|
|
177
156
|
|
|
178
157
|
if not value and not message:
|
|
179
158
|
logger.warning(
|
|
180
|
-
"No information is available to report the
|
|
159
|
+
"No information is available to report the progress"
|
|
181
160
|
)
|
|
182
161
|
return
|
|
183
162
|
|
|
@@ -185,14 +164,12 @@ class LocalAnalysisContext:
|
|
|
185
164
|
value = int(value) # Cast to int to avoid float/string problems
|
|
186
165
|
if value > 100:
|
|
187
166
|
logger.warning(
|
|
188
|
-
"The progress value should be between 0 and 100 (using "
|
|
189
|
-
"100 instead)"
|
|
167
|
+
"The progress value should be between 0 and 100 (using 100 instead)"
|
|
190
168
|
)
|
|
191
169
|
value = 100
|
|
192
170
|
elif value < 0:
|
|
193
171
|
logger.warning(
|
|
194
|
-
"The progress value should be between 0 and 100 "
|
|
195
|
-
"(using 0 instead)"
|
|
172
|
+
"The progress value should be between 0 and 100 (using 0 instead)"
|
|
196
173
|
)
|
|
197
174
|
value = 0
|
|
198
175
|
|
|
@@ -207,7 +184,6 @@ class LocalAnalysisContext:
|
|
|
207
184
|
dict
|
|
208
185
|
Settings for the current analysis.
|
|
209
186
|
"""
|
|
210
|
-
|
|
211
187
|
return self.__settings
|
|
212
188
|
|
|
213
189
|
def get_files(
|
|
@@ -218,11 +194,9 @@ class LocalAnalysisContext:
|
|
|
218
194
|
reg_expression=None,
|
|
219
195
|
file_filter_condition_name=None,
|
|
220
196
|
subject_container_id=None,
|
|
221
|
-
unpack=True,
|
|
222
197
|
):
|
|
223
198
|
"""
|
|
224
|
-
Returns the files in the input container specified by `input_id`
|
|
225
|
-
that match the modality, tags
|
|
199
|
+
Returns the files in the input container specified by `input_id` that match the modality, tags
|
|
226
200
|
and regular expression, if any.
|
|
227
201
|
|
|
228
202
|
Parameters
|
|
@@ -233,13 +207,11 @@ class LocalAnalysisContext:
|
|
|
233
207
|
Optional modality, will allow any modalities if None given.
|
|
234
208
|
Default is None.
|
|
235
209
|
tags : set, optional
|
|
236
|
-
Optional set of tags, will allow any tags if None given,
|
|
237
|
-
and will match any set of tags (including
|
|
210
|
+
Optional set of tags, will allow any tags if None given, and will match any set of tags (including
|
|
238
211
|
the empty set) otherwise.
|
|
239
212
|
Default is None.
|
|
240
213
|
reg_expression : str, optional
|
|
241
|
-
Regular expression to match with the file names in the
|
|
242
|
-
specified container, will allow any file names
|
|
214
|
+
Regular expression to match with the file names in the specified container, will allow any file names
|
|
243
215
|
if None given.
|
|
244
216
|
Default is None.
|
|
245
217
|
file_filter_condition_name : str, optional
|
|
@@ -251,7 +223,6 @@ class LocalAnalysisContext:
|
|
|
251
223
|
list of File
|
|
252
224
|
List of selected file handlers from the container.
|
|
253
225
|
"""
|
|
254
|
-
|
|
255
226
|
logger = logging.getLogger(__name__)
|
|
256
227
|
logger.info(
|
|
257
228
|
"Get files: {} [modality={} / tags={} / regex={}]".format(
|
|
@@ -262,18 +233,15 @@ class LocalAnalysisContext:
|
|
|
262
233
|
file_handlers = []
|
|
263
234
|
|
|
264
235
|
# Create File
|
|
265
|
-
|
|
266
236
|
for file_description in self.__settings[input_id]:
|
|
267
237
|
if "path" not in file_description:
|
|
268
|
-
msg = (
|
|
269
|
-
|
|
270
|
-
" {}".format(input_id)
|
|
238
|
+
msg = 'Cannot find the key "path" for the input container {}'.format(
|
|
239
|
+
input_id
|
|
271
240
|
)
|
|
272
241
|
logger.error(msg)
|
|
273
242
|
raise RuntimeError(msg)
|
|
274
243
|
|
|
275
244
|
# Use file_filter_condition_name if available
|
|
276
|
-
|
|
277
245
|
if file_filter_condition_name:
|
|
278
246
|
if "file_filter_condition_name" not in file_description:
|
|
279
247
|
continue # Skip
|
|
@@ -340,7 +308,6 @@ class LocalAnalysisContext:
|
|
|
340
308
|
protocol : None
|
|
341
309
|
container_id : None
|
|
342
310
|
"""
|
|
343
|
-
|
|
344
311
|
logger = logging.getLogger(__name__)
|
|
345
312
|
if tags:
|
|
346
313
|
logger.warning("Tags ignored (local execution): {}".format(tags))
|
|
@@ -376,8 +343,7 @@ class LocalAnalysisContext:
|
|
|
376
343
|
|
|
377
344
|
def download_resource(self, resource_path, destination_path):
|
|
378
345
|
"""
|
|
379
|
-
Downloads a file from the user/group tool resources. The resource
|
|
380
|
-
path can include subdirectories and must
|
|
346
|
+
Downloads a file from the user/group tool resources. The resource path can include subdirectories and must
|
|
381
347
|
be relative:
|
|
382
348
|
Downloads a resource file to the container.
|
|
383
349
|
|
|
@@ -388,7 +354,6 @@ class LocalAnalysisContext:
|
|
|
388
354
|
destination_path : str
|
|
389
355
|
Path where the file will be downloaded to
|
|
390
356
|
"""
|
|
391
|
-
|
|
392
357
|
logger = logging.getLogger(__name__)
|
|
393
358
|
logger.info(self.__res_folder)
|
|
394
359
|
if not self.__res_folder: # Default keyword for external users
|
|
@@ -396,12 +361,14 @@ class LocalAnalysisContext:
|
|
|
396
361
|
return
|
|
397
362
|
else:
|
|
398
363
|
logger.info(
|
|
399
|
-
"Mocking resources from directory:"
|
|
400
|
-
|
|
364
|
+
"Mocking resources from directory: {}".format(
|
|
365
|
+
self.__res_folder
|
|
366
|
+
)
|
|
401
367
|
)
|
|
402
368
|
logger.info(
|
|
403
|
-
"The selected mode ({}) is ignored in local "
|
|
404
|
-
|
|
369
|
+
"The selected mode ({}) is ignored in local execution.".format(
|
|
370
|
+
type
|
|
371
|
+
)
|
|
405
372
|
)
|
|
406
373
|
|
|
407
374
|
logger.info(
|
|
@@ -422,20 +389,17 @@ class LocalAnalysisContext:
|
|
|
422
389
|
|
|
423
390
|
def _get_manual_analysis_data(self):
|
|
424
391
|
"""
|
|
425
|
-
Returns a dictionary with the manual analysis data generated during
|
|
426
|
-
the manual step (user interaction)
|
|
392
|
+
Returns a dictionary with the manual analysis data generated during the manual step (user interaction)
|
|
427
393
|
|
|
428
394
|
Returns
|
|
429
395
|
-------
|
|
430
396
|
dict
|
|
431
397
|
The values generated during the manual step.
|
|
432
398
|
"""
|
|
433
|
-
|
|
434
399
|
logger = logging.getLogger(__name__)
|
|
435
400
|
logger.info("Getting manual analysis data")
|
|
436
401
|
logger.warning(
|
|
437
|
-
"Getting manual analysis data is not supported locally. "
|
|
438
|
-
"Skipping..."
|
|
402
|
+
"Getting manual analysis data is not supported locally. Skipping..."
|
|
439
403
|
)
|
|
440
404
|
return {}
|
|
441
405
|
|
|
@@ -460,10 +424,8 @@ class LocalAnalysisContext:
|
|
|
460
424
|
title : str, optional
|
|
461
425
|
How the metadata field should be presented
|
|
462
426
|
readonly : bool, optional
|
|
463
|
-
Whether the user should be able to edit the value on the platform
|
|
464
|
-
or not (only by analyses)
|
|
427
|
+
Whether the user should be able to edit the value on the platform or not (only by analyses)
|
|
465
428
|
"""
|
|
466
|
-
|
|
467
429
|
logger = logging.getLogger(__name__)
|
|
468
430
|
|
|
469
431
|
assert isinstance(key, str)
|
|
@@ -482,20 +444,13 @@ class LocalAnalysisContext:
|
|
|
482
444
|
"Invalid type for the metadata value: {!r}".format(type(value))
|
|
483
445
|
)
|
|
484
446
|
|
|
485
|
-
logger.info(
|
|
486
|
-
"Setting metadata parameter: {} =" "{!r}".format(key, value)
|
|
487
|
-
)
|
|
447
|
+
logger.info("Setting metadata parameter: {} = {!r}".format(key, value))
|
|
488
448
|
logger.warning(
|
|
489
|
-
"Setting metadata values is not supported locally.
|
|
449
|
+
"Setting metadata values is not supported locally. Skipping..."
|
|
490
450
|
)
|
|
491
451
|
return None
|
|
492
452
|
|
|
493
|
-
def get_metadata_value(
|
|
494
|
-
self,
|
|
495
|
-
key,
|
|
496
|
-
patient_secret_name=None,
|
|
497
|
-
ssid=None,
|
|
498
|
-
):
|
|
453
|
+
def get_metadata_value(self, key, patient_secret_name=None, ssid=None):
|
|
499
454
|
"""
|
|
500
455
|
Gets the value of a metadata parameter for the current session
|
|
501
456
|
|
|
@@ -512,30 +467,26 @@ class LocalAnalysisContext:
|
|
|
512
467
|
-------
|
|
513
468
|
The value of the parameter if it exists, None otherwise
|
|
514
469
|
"""
|
|
515
|
-
|
|
516
470
|
logger = logging.getLogger(__name__)
|
|
517
471
|
logger.info("Getting metadata value: {}".format(key))
|
|
518
472
|
logger.warning(
|
|
519
|
-
"Getting metadata values is not supported locally.
|
|
473
|
+
"Getting metadata values is not supported locally. Skipping..."
|
|
520
474
|
)
|
|
521
475
|
return None
|
|
522
476
|
|
|
523
477
|
def _assure_metadata_parameters(self, params):
|
|
524
478
|
"""
|
|
525
|
-
Check whether a metadata parameter exists, creating it if not.
|
|
526
|
-
Not supported for local testing.
|
|
479
|
+
Check whether a metadata parameter exists, creating it if not. Not supported for local testing.
|
|
527
480
|
|
|
528
481
|
Parameters
|
|
529
482
|
----------
|
|
530
483
|
params : dict
|
|
531
|
-
The definition of the parameter. It may contain "title", "type",
|
|
532
|
-
"visible", "readonly" or "order".
|
|
484
|
+
The definition of the parameter. It may contain "title", "type", "visible", "readonly" or "order".
|
|
533
485
|
"""
|
|
534
|
-
|
|
535
486
|
logger = logging.getLogger(__name__)
|
|
536
487
|
logger.info("Setting metadata param (ckeck): {}".format(params))
|
|
537
488
|
logger.warning(
|
|
538
|
-
"Assuring metadata params is not supported locally.
|
|
489
|
+
"Assuring metadata params is not supported locally. Skipping..."
|
|
539
490
|
)
|
|
540
491
|
|
|
541
492
|
def set_analysis_output_variables(
|
|
@@ -551,26 +502,15 @@ class LocalAnalysisContext:
|
|
|
551
502
|
clear_previous : bool, optional
|
|
552
503
|
Whether the previous output variables should be cleared or not
|
|
553
504
|
"""
|
|
554
|
-
|
|
555
505
|
logger = logging.getLogger(__name__)
|
|
556
506
|
logger.warning("Output variables not supported locally. Skipping...")
|
|
557
507
|
|
|
558
508
|
|
|
559
509
|
class LocalFile:
|
|
560
|
-
|
|
561
|
-
def __init__(
|
|
562
|
-
self,
|
|
563
|
-
name,
|
|
564
|
-
input_container_path,
|
|
565
|
-
modality,
|
|
566
|
-
tags,
|
|
567
|
-
file_info,
|
|
568
|
-
):
|
|
510
|
+
def __init__(self, name, input_container_path, modality, tags, file_info):
|
|
569
511
|
"""
|
|
570
|
-
Object that represents a file and all its metadata in the platform.
|
|
571
|
-
Should not be created directly.
|
|
512
|
+
Object that represents a file and all its metadata in the platform. Should not be created directly.
|
|
572
513
|
"""
|
|
573
|
-
|
|
574
514
|
self.name = name
|
|
575
515
|
self.__input_container_path = input_container_path
|
|
576
516
|
self.__download_path = None
|
|
@@ -587,7 +527,6 @@ class LocalFile:
|
|
|
587
527
|
str or None
|
|
588
528
|
Modality of the file or None if not known.
|
|
589
529
|
"""
|
|
590
|
-
|
|
591
530
|
return self.__modality
|
|
592
531
|
|
|
593
532
|
@staticmethod
|
|
@@ -600,23 +539,18 @@ class LocalFile:
|
|
|
600
539
|
str or None
|
|
601
540
|
File format or None if not known.
|
|
602
541
|
"""
|
|
603
|
-
|
|
604
542
|
return None
|
|
605
543
|
|
|
606
544
|
def get_file_info(self):
|
|
607
545
|
"""
|
|
608
|
-
Get the file information. The type of information depends on the type
|
|
609
|
-
|
|
610
|
-
(e.g. nifti files include information such as 'Data strides',
|
|
611
|
-
'Data type', 'Dimensions' or 'Voxel size').
|
|
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').
|
|
612
548
|
|
|
613
549
|
Returns
|
|
614
550
|
-------
|
|
615
551
|
dict
|
|
616
|
-
Dictionary of key-value pairs that depend on the format of the
|
|
617
|
-
file.
|
|
552
|
+
Dictionary of key-value pairs that depend on the format of the file.
|
|
618
553
|
"""
|
|
619
|
-
|
|
620
554
|
return self.__file_info
|
|
621
555
|
|
|
622
556
|
def get_file_tags(self):
|
|
@@ -628,7 +562,6 @@ class LocalFile:
|
|
|
628
562
|
set
|
|
629
563
|
Set of tags associated to this file
|
|
630
564
|
"""
|
|
631
|
-
|
|
632
565
|
return self.__tags
|
|
633
566
|
|
|
634
567
|
def get_file_path(self):
|
|
@@ -645,11 +578,9 @@ class LocalFile:
|
|
|
645
578
|
RuntimeError
|
|
646
579
|
If `get_file_path` is called before the file has been downloaded
|
|
647
580
|
"""
|
|
648
|
-
|
|
649
581
|
if self.__download_path is None:
|
|
650
|
-
err_msg = (
|
|
651
|
-
|
|
652
|
-
"downloaded".format(self.name)
|
|
582
|
+
err_msg = "File {!r} has no path because it has not been downloaded".format(
|
|
583
|
+
self.name
|
|
653
584
|
)
|
|
654
585
|
logging.getLogger(__name__).error(err_msg)
|
|
655
586
|
raise RuntimeError(err_msg)
|
|
@@ -665,7 +596,6 @@ class LocalFile:
|
|
|
665
596
|
destination_file_path : str
|
|
666
597
|
Path where the file should be downloaded.
|
|
667
598
|
"""
|
|
668
|
-
|
|
669
599
|
logger = logging.getLogger(__name__)
|
|
670
600
|
logger.info(
|
|
671
601
|
"Downloading {!r} to {!r}".format(self.name, destination_file_path)
|
|
@@ -677,37 +607,30 @@ class LocalFile:
|
|
|
677
607
|
|
|
678
608
|
def download(self, dest_path, unpack=True):
|
|
679
609
|
"""
|
|
680
|
-
Downloads a file or the contents of a packed file to to the specified
|
|
681
|
-
`path`.
|
|
610
|
+
Downloads a file or the contents of a packed file to to the specified `path`.
|
|
682
611
|
|
|
683
612
|
Parameters
|
|
684
613
|
----------
|
|
685
614
|
dest_path:
|
|
686
615
|
Path where the file should be downloaded to.
|
|
687
616
|
unpack:
|
|
688
|
-
Tells the function whether the file should be unpacked to the
|
|
689
|
-
given folder.
|
|
617
|
+
Tells the function whether the file should be unpacked to the given folder.
|
|
690
618
|
|
|
691
619
|
Returns
|
|
692
620
|
-------
|
|
693
621
|
str:
|
|
694
622
|
The full path of the file or the folder with the unpacked files.
|
|
695
623
|
"""
|
|
696
|
-
|
|
697
624
|
logger = logging.getLogger(__name__)
|
|
698
625
|
source_file = self.name
|
|
699
626
|
|
|
700
627
|
# Normalize path
|
|
701
|
-
|
|
702
628
|
dest_path = os.path.abspath(dest_path)
|
|
703
629
|
|
|
704
630
|
logger.debug("Using path {!r}".format(dest_path))
|
|
705
631
|
|
|
706
632
|
if source_file.endswith(".zip") and unpack:
|
|
707
|
-
|
|
708
|
-
# Download the zip to a temporary directory and unpack its
|
|
709
|
-
# contents to the user dir path
|
|
710
|
-
|
|
633
|
+
# Download the zip to a temporary directory and unpack its contents to the user dir path
|
|
711
634
|
with TemporaryDirectory() as temp_dir:
|
|
712
635
|
temp_path = os.path.join(temp_dir, source_file)
|
|
713
636
|
self.__download_file(temp_path)
|
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/bids/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/bids/wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/communication.py
RENAMED
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/directory_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/__init__.py
RENAMED
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/client.py
RENAMED
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/local/executor.py
RENAMED
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/log_capture.py
RENAMED
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/make_entrypoint.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qmenta_sdk_lib-2.0.1.dev3469 → qmenta_sdk_lib-2.0.1.dev3470}/python/qmenta/sdk/tool_maker/inputs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|