dkist-processing-common 10.5.4__py3-none-any.whl → 12.1.0rc1__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.
- changelog/280.misc.rst +1 -0
- changelog/282.feature.2.rst +2 -0
- changelog/282.feature.rst +2 -0
- changelog/284.feature.rst +1 -0
- changelog/285.feature.rst +2 -0
- changelog/285.misc.rst +2 -0
- changelog/286.feature.rst +2 -0
- changelog/287.misc.rst +1 -0
- dkist_processing_common/__init__.py +1 -0
- dkist_processing_common/_util/constants.py +1 -0
- dkist_processing_common/_util/graphql.py +1 -0
- dkist_processing_common/_util/scratch.py +9 -9
- dkist_processing_common/_util/tags.py +1 -0
- dkist_processing_common/codecs/array.py +20 -0
- dkist_processing_common/codecs/asdf.py +9 -3
- dkist_processing_common/codecs/basemodel.py +22 -0
- dkist_processing_common/codecs/bytes.py +1 -0
- dkist_processing_common/codecs/fits.py +37 -9
- dkist_processing_common/codecs/iobase.py +1 -0
- dkist_processing_common/codecs/json.py +1 -0
- dkist_processing_common/codecs/path.py +1 -0
- dkist_processing_common/codecs/quality.py +1 -1
- dkist_processing_common/codecs/str.py +1 -0
- dkist_processing_common/config.py +64 -25
- dkist_processing_common/manual.py +6 -8
- dkist_processing_common/models/constants.py +373 -37
- dkist_processing_common/models/dkist_location.py +27 -0
- dkist_processing_common/models/fits_access.py +48 -0
- dkist_processing_common/models/flower_pot.py +231 -9
- dkist_processing_common/models/fried_parameter.py +41 -0
- dkist_processing_common/models/graphql.py +66 -75
- dkist_processing_common/models/input_dataset.py +117 -0
- dkist_processing_common/models/message.py +1 -1
- dkist_processing_common/models/message_queue_binding.py +1 -1
- dkist_processing_common/models/metric_code.py +2 -0
- dkist_processing_common/models/parameters.py +65 -28
- dkist_processing_common/models/quality.py +50 -5
- dkist_processing_common/models/tags.py +23 -21
- dkist_processing_common/models/task_name.py +3 -2
- dkist_processing_common/models/telemetry.py +28 -0
- dkist_processing_common/models/wavelength.py +3 -1
- dkist_processing_common/parsers/average_bud.py +46 -0
- dkist_processing_common/parsers/cs_step.py +13 -12
- dkist_processing_common/parsers/dsps_repeat.py +6 -4
- dkist_processing_common/parsers/experiment_id_bud.py +12 -4
- dkist_processing_common/parsers/id_bud.py +42 -27
- dkist_processing_common/parsers/l0_fits_access.py +5 -3
- dkist_processing_common/parsers/l1_fits_access.py +51 -23
- dkist_processing_common/parsers/lookup_bud.py +125 -0
- dkist_processing_common/parsers/near_bud.py +21 -20
- dkist_processing_common/parsers/observing_program_id_bud.py +24 -0
- dkist_processing_common/parsers/proposal_id_bud.py +13 -5
- dkist_processing_common/parsers/quality.py +2 -0
- dkist_processing_common/parsers/retarder.py +32 -0
- dkist_processing_common/parsers/single_value_single_key_flower.py +6 -1
- dkist_processing_common/parsers/task.py +8 -6
- dkist_processing_common/parsers/time.py +178 -72
- dkist_processing_common/parsers/unique_bud.py +21 -22
- dkist_processing_common/parsers/wavelength.py +5 -3
- dkist_processing_common/tasks/__init__.py +3 -2
- dkist_processing_common/tasks/assemble_movie.py +4 -3
- dkist_processing_common/tasks/base.py +59 -60
- dkist_processing_common/tasks/l1_output_data.py +54 -53
- dkist_processing_common/tasks/mixin/globus.py +24 -27
- dkist_processing_common/tasks/mixin/interservice_bus.py +1 -0
- dkist_processing_common/tasks/mixin/metadata_store.py +108 -243
- dkist_processing_common/tasks/mixin/object_store.py +22 -0
- dkist_processing_common/tasks/mixin/quality/__init__.py +1 -0
- dkist_processing_common/tasks/mixin/quality/_base.py +8 -1
- dkist_processing_common/tasks/mixin/quality/_metrics.py +166 -14
- dkist_processing_common/tasks/output_data_base.py +4 -3
- dkist_processing_common/tasks/parse_l0_input_data.py +277 -15
- dkist_processing_common/tasks/quality_metrics.py +9 -9
- dkist_processing_common/tasks/teardown.py +7 -7
- dkist_processing_common/tasks/transfer_input_data.py +67 -69
- dkist_processing_common/tasks/trial_catalog.py +77 -17
- dkist_processing_common/tasks/trial_output_data.py +16 -17
- dkist_processing_common/tasks/write_l1.py +102 -72
- dkist_processing_common/tests/conftest.py +32 -173
- dkist_processing_common/tests/mock_metadata_store.py +271 -0
- dkist_processing_common/tests/test_assemble_movie.py +4 -4
- dkist_processing_common/tests/test_assemble_quality.py +32 -4
- dkist_processing_common/tests/test_base.py +5 -19
- dkist_processing_common/tests/test_codecs.py +103 -12
- dkist_processing_common/tests/test_constants.py +15 -0
- dkist_processing_common/tests/test_dkist_location.py +15 -0
- dkist_processing_common/tests/test_fits_access.py +56 -19
- dkist_processing_common/tests/test_flower_pot.py +147 -5
- dkist_processing_common/tests/test_fried_parameter.py +27 -0
- dkist_processing_common/tests/test_input_dataset.py +78 -361
- dkist_processing_common/tests/test_interservice_bus.py +1 -0
- dkist_processing_common/tests/test_interservice_bus_mixin.py +1 -1
- dkist_processing_common/tests/test_manual_processing.py +33 -0
- dkist_processing_common/tests/test_output_data_base.py +5 -7
- dkist_processing_common/tests/test_parameters.py +71 -22
- dkist_processing_common/tests/test_parse_l0_input_data.py +115 -32
- dkist_processing_common/tests/test_publish_catalog_messages.py +2 -24
- dkist_processing_common/tests/test_quality.py +1 -0
- dkist_processing_common/tests/test_quality_mixin.py +255 -23
- dkist_processing_common/tests/test_scratch.py +2 -1
- dkist_processing_common/tests/test_stems.py +511 -168
- dkist_processing_common/tests/test_submit_dataset_metadata.py +3 -7
- dkist_processing_common/tests/test_tags.py +1 -0
- dkist_processing_common/tests/test_task_name.py +1 -1
- dkist_processing_common/tests/test_task_parsing.py +17 -7
- dkist_processing_common/tests/test_teardown.py +28 -24
- dkist_processing_common/tests/test_transfer_input_data.py +270 -125
- dkist_processing_common/tests/test_transfer_l1_output_data.py +2 -3
- dkist_processing_common/tests/test_trial_catalog.py +83 -8
- dkist_processing_common/tests/test_trial_output_data.py +46 -73
- dkist_processing_common/tests/test_workflow_task_base.py +8 -10
- dkist_processing_common/tests/test_write_l1.py +298 -76
- dkist_processing_common-12.1.0rc1.dist-info/METADATA +265 -0
- dkist_processing_common-12.1.0rc1.dist-info/RECORD +134 -0
- {dkist_processing_common-10.5.4.dist-info → dkist_processing_common-12.1.0rc1.dist-info}/WHEEL +1 -1
- docs/conf.py +1 -0
- docs/index.rst +1 -1
- docs/landing_page.rst +13 -0
- dkist_processing_common/tasks/mixin/input_dataset.py +0 -166
- dkist_processing_common-10.5.4.dist-info/METADATA +0 -175
- dkist_processing_common-10.5.4.dist-info/RECORD +0 -112
- {dkist_processing_common-10.5.4.dist-info → dkist_processing_common-12.1.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from copy import copy
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from pathlib import Path
|
|
5
2
|
from typing import Any
|
|
6
3
|
from uuid import uuid4
|
|
7
4
|
|
|
8
5
|
import pytest
|
|
9
6
|
|
|
7
|
+
from dkist_processing_common.codecs.basemodel import basemodel_decoder
|
|
8
|
+
from dkist_processing_common.models.input_dataset import InputDatasetPartDocumentList
|
|
10
9
|
from dkist_processing_common.models.tags import Tag
|
|
11
|
-
from dkist_processing_common.
|
|
12
|
-
from dkist_processing_common.tasks.mixin.input_dataset import InputDatasetObject
|
|
13
|
-
from dkist_processing_common.tests.conftest import create_parameter_files
|
|
14
|
-
from dkist_processing_common.tests.conftest import InputDatasetTask
|
|
10
|
+
from dkist_processing_common.tests.mock_metadata_store import input_dataset_parameters_part_factory
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
def input_dataset_frames_part_factory(bucket_count: int = 1) -> list[dict]:
|
|
@@ -29,136 +25,45 @@ def flatten_frame_parts(frame_parts: list[dict]) -> list[tuple[str, str]]:
|
|
|
29
25
|
return result
|
|
30
26
|
|
|
31
27
|
|
|
32
|
-
def input_dataset_parameters_part_factory(
|
|
33
|
-
parameter_count: int = 1,
|
|
34
|
-
parameter_value_count: int = 1,
|
|
35
|
-
has_date: bool = False,
|
|
36
|
-
has_file: bool = False,
|
|
37
|
-
) -> list[dict]:
|
|
38
|
-
result = [
|
|
39
|
-
{
|
|
40
|
-
"parameterName": uuid4().hex[:6],
|
|
41
|
-
"parameterValues": [
|
|
42
|
-
{"parameterValueId": i, "parameterValue": json.dumps(uuid4().hex)}
|
|
43
|
-
for i in range(parameter_value_count)
|
|
44
|
-
],
|
|
45
|
-
}
|
|
46
|
-
for _ in range(parameter_count)
|
|
47
|
-
]
|
|
48
|
-
if has_date:
|
|
49
|
-
for data in result:
|
|
50
|
-
data["parameterValueStartDate"] = datetime(2022, 9, 14).isoformat()[:10]
|
|
51
|
-
if has_file:
|
|
52
|
-
for data in result:
|
|
53
|
-
param_list = data["parameterValues"]
|
|
54
|
-
for item in param_list:
|
|
55
|
-
item["parameterValue"] = json.dumps(
|
|
56
|
-
{
|
|
57
|
-
"__file__": {
|
|
58
|
-
"bucket": "data",
|
|
59
|
-
"objectKey": f"parameters/{data['parameterName']}/{uuid4().hex}.dat",
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
)
|
|
63
|
-
return result
|
|
64
|
-
|
|
65
|
-
|
|
66
28
|
@pytest.mark.parametrize(
|
|
67
29
|
"input_dataset_parts",
|
|
68
30
|
[
|
|
69
|
-
pytest.param((None, Tag.input_dataset_observe_frames()), id="empty"),
|
|
70
31
|
pytest.param(
|
|
71
32
|
(input_dataset_frames_part_factory(), Tag.input_dataset_observe_frames()),
|
|
72
|
-
id="
|
|
33
|
+
id="observe_single_bucket",
|
|
73
34
|
),
|
|
74
35
|
pytest.param(
|
|
75
36
|
(input_dataset_frames_part_factory(bucket_count=2), Tag.input_dataset_observe_frames()),
|
|
76
|
-
id="
|
|
37
|
+
id="observe_multi_bucket",
|
|
77
38
|
),
|
|
78
|
-
],
|
|
79
|
-
)
|
|
80
|
-
def test_input_dataset_observe_frames_part_document(
|
|
81
|
-
task_with_input_dataset, input_dataset_parts: tuple[Any, str]
|
|
82
|
-
):
|
|
83
|
-
"""
|
|
84
|
-
Given: A task with an input dataset observe frames part document tagged as such
|
|
85
|
-
When: Accessing the document via the InputDatasetMixIn
|
|
86
|
-
Then: The contents of the file are returned
|
|
87
|
-
"""
|
|
88
|
-
doc_part, _ = input_dataset_parts
|
|
89
|
-
task = task_with_input_dataset
|
|
90
|
-
assert task.input_dataset_observe_frames_part_document == doc_part
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
@pytest.mark.parametrize(
|
|
94
|
-
"input_dataset_parts",
|
|
95
|
-
[
|
|
96
|
-
pytest.param((None, Tag.input_dataset_calibration_frames()), id="empty"),
|
|
97
39
|
pytest.param(
|
|
98
40
|
(input_dataset_frames_part_factory(), Tag.input_dataset_calibration_frames()),
|
|
99
|
-
id="
|
|
41
|
+
id="calib_single_bucket",
|
|
100
42
|
),
|
|
101
43
|
pytest.param(
|
|
102
44
|
(
|
|
103
45
|
input_dataset_frames_part_factory(bucket_count=2),
|
|
104
46
|
Tag.input_dataset_calibration_frames(),
|
|
105
47
|
),
|
|
106
|
-
id="
|
|
107
|
-
),
|
|
108
|
-
],
|
|
109
|
-
)
|
|
110
|
-
def test_input_dataset_calibration_frames_part_document(
|
|
111
|
-
task_with_input_dataset, input_dataset_parts: tuple[Any, str]
|
|
112
|
-
):
|
|
113
|
-
"""
|
|
114
|
-
Given: A task with an input dataset calibration frames part document tagged as such
|
|
115
|
-
When: Accessing the document via the InputDatasetMixIn
|
|
116
|
-
Then: The contents of the file are returned
|
|
117
|
-
"""
|
|
118
|
-
doc_part, _ = input_dataset_parts
|
|
119
|
-
task = task_with_input_dataset
|
|
120
|
-
assert task.input_dataset_calibration_frames_part_document == doc_part
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
@pytest.mark.parametrize(
|
|
124
|
-
"input_dataset_parts",
|
|
125
|
-
[
|
|
126
|
-
pytest.param((None, Tag.input_dataset_parameters()), id="empty"),
|
|
127
|
-
pytest.param(
|
|
128
|
-
(input_dataset_parameters_part_factory(), Tag.input_dataset_parameters()),
|
|
129
|
-
id="single_param_no_date",
|
|
130
|
-
),
|
|
131
|
-
pytest.param(
|
|
132
|
-
(
|
|
133
|
-
input_dataset_parameters_part_factory(parameter_count=2),
|
|
134
|
-
Tag.input_dataset_parameters(),
|
|
135
|
-
),
|
|
136
|
-
id="multi_param_no_date",
|
|
137
|
-
),
|
|
138
|
-
pytest.param(
|
|
139
|
-
(input_dataset_parameters_part_factory(has_date=True), Tag.input_dataset_parameters()),
|
|
140
|
-
id="single_param_with_date",
|
|
141
|
-
),
|
|
142
|
-
pytest.param(
|
|
143
|
-
(
|
|
144
|
-
input_dataset_parameters_part_factory(parameter_count=2, has_date=True),
|
|
145
|
-
Tag.input_dataset_parameters(),
|
|
146
|
-
),
|
|
147
|
-
id="multi_param_with_date",
|
|
48
|
+
id="calib_multi_bucket",
|
|
148
49
|
),
|
|
149
50
|
],
|
|
150
51
|
)
|
|
151
|
-
def
|
|
52
|
+
def test_input_dataset_frames_part_document(
|
|
152
53
|
task_with_input_dataset, input_dataset_parts: tuple[Any, str]
|
|
153
54
|
):
|
|
154
55
|
"""
|
|
155
|
-
Given: A task with an input dataset
|
|
156
|
-
When:
|
|
157
|
-
Then: The contents of the file are
|
|
56
|
+
Given: A task with an input dataset frames part document already written to file
|
|
57
|
+
When: Reading the file into a validated model
|
|
58
|
+
Then: The correct contents of the file are loaded
|
|
158
59
|
"""
|
|
159
|
-
doc_part,
|
|
60
|
+
doc_part, tag = input_dataset_parts
|
|
160
61
|
task = task_with_input_dataset
|
|
161
|
-
|
|
62
|
+
doc_from_file = next(
|
|
63
|
+
task.read(tags=tag, decoder=basemodel_decoder, model=InputDatasetPartDocumentList)
|
|
64
|
+
)
|
|
65
|
+
frames = [frames.model_dump() for frames in doc_from_file.doc_list]
|
|
66
|
+
assert frames == doc_part
|
|
162
67
|
|
|
163
68
|
|
|
164
69
|
@pytest.mark.parametrize(
|
|
@@ -174,24 +79,15 @@ def test_input_dataset_parameters_part_document(
|
|
|
174
79
|
pytest.param(
|
|
175
80
|
[
|
|
176
81
|
(input_dataset_frames_part_factory(), Tag.input_dataset_observe_frames()),
|
|
177
|
-
(None, Tag.input_dataset_calibration_frames()),
|
|
178
82
|
],
|
|
179
83
|
id="observe1_cal0_single_bucket",
|
|
180
84
|
),
|
|
181
85
|
pytest.param(
|
|
182
86
|
[
|
|
183
|
-
(None, Tag.input_dataset_observe_frames()),
|
|
184
87
|
(input_dataset_frames_part_factory(), Tag.input_dataset_calibration_frames()),
|
|
185
88
|
],
|
|
186
89
|
id="observe0_cal1_single_bucket",
|
|
187
90
|
),
|
|
188
|
-
pytest.param(
|
|
189
|
-
[
|
|
190
|
-
(None, Tag.input_dataset_observe_frames()),
|
|
191
|
-
(None, Tag.input_dataset_calibration_frames()),
|
|
192
|
-
],
|
|
193
|
-
id="observe0_cal0_single_bucket",
|
|
194
|
-
),
|
|
195
91
|
pytest.param(
|
|
196
92
|
[
|
|
197
93
|
(
|
|
@@ -211,13 +107,11 @@ def test_input_dataset_parameters_part_document(
|
|
|
211
107
|
input_dataset_frames_part_factory(bucket_count=2),
|
|
212
108
|
Tag.input_dataset_observe_frames(),
|
|
213
109
|
),
|
|
214
|
-
(None, Tag.input_dataset_calibration_frames()),
|
|
215
110
|
],
|
|
216
111
|
id="observe1_cal0_multi_bucket",
|
|
217
112
|
),
|
|
218
113
|
pytest.param(
|
|
219
114
|
[
|
|
220
|
-
(None, Tag.input_dataset_observe_frames()),
|
|
221
115
|
(
|
|
222
116
|
input_dataset_frames_part_factory(bucket_count=2),
|
|
223
117
|
Tag.input_dataset_calibration_frames(),
|
|
@@ -225,21 +119,17 @@ def test_input_dataset_parameters_part_document(
|
|
|
225
119
|
],
|
|
226
120
|
id="observe0_cal1_multi_bucket",
|
|
227
121
|
),
|
|
228
|
-
pytest.param(
|
|
229
|
-
[
|
|
230
|
-
(None, Tag.input_dataset_observe_frames()),
|
|
231
|
-
(None, Tag.input_dataset_calibration_frames()),
|
|
232
|
-
],
|
|
233
|
-
id="observe0_cal0_multi_bucket",
|
|
234
|
-
),
|
|
235
122
|
],
|
|
236
123
|
)
|
|
237
|
-
def
|
|
124
|
+
def test_input_dataset_frames_combination(
|
|
125
|
+
task_with_input_dataset, input_dataset_parts: list[tuple[Any, str]]
|
|
126
|
+
):
|
|
238
127
|
"""
|
|
239
|
-
Given:
|
|
240
|
-
When:
|
|
241
|
-
Then:
|
|
128
|
+
Given: A task with both types of input dataset frame documents written to files
|
|
129
|
+
When: Reading the file and validating into models
|
|
130
|
+
Then: The correct files are returned by the input_dataset_objects method of InputDatasetFrames
|
|
242
131
|
"""
|
|
132
|
+
# Given
|
|
243
133
|
doc_parts = [part for part, _ in input_dataset_parts]
|
|
244
134
|
task = task_with_input_dataset
|
|
245
135
|
expected = []
|
|
@@ -247,7 +137,29 @@ def test_input_dataset_frames(task_with_input_dataset, input_dataset_parts: list
|
|
|
247
137
|
if part:
|
|
248
138
|
expected.extend(flatten_frame_parts(part))
|
|
249
139
|
expected_set = set(expected)
|
|
250
|
-
|
|
140
|
+
# When
|
|
141
|
+
frames = []
|
|
142
|
+
observe_frames = next(
|
|
143
|
+
task.read(
|
|
144
|
+
tags=Tag.input_dataset_observe_frames(),
|
|
145
|
+
decoder=basemodel_decoder,
|
|
146
|
+
model=InputDatasetPartDocumentList,
|
|
147
|
+
),
|
|
148
|
+
None,
|
|
149
|
+
)
|
|
150
|
+
frames += observe_frames.doc_list if observe_frames else []
|
|
151
|
+
calibration_frames = next(
|
|
152
|
+
task.read(
|
|
153
|
+
tags=Tag.input_dataset_calibration_frames(),
|
|
154
|
+
decoder=basemodel_decoder,
|
|
155
|
+
model=InputDatasetPartDocumentList,
|
|
156
|
+
),
|
|
157
|
+
None,
|
|
158
|
+
)
|
|
159
|
+
frames += calibration_frames.doc_list if calibration_frames else []
|
|
160
|
+
# Then
|
|
161
|
+
frames_objects = sum([f.input_dataset_objects for f in frames], [])
|
|
162
|
+
actual = [(frame.bucket, frame.object_key) for frame in frames_objects]
|
|
251
163
|
actual_set = set(actual)
|
|
252
164
|
assert len(actual) == len(actual_set)
|
|
253
165
|
assert actual_set.difference(expected_set) == set()
|
|
@@ -256,132 +168,45 @@ def test_input_dataset_frames(task_with_input_dataset, input_dataset_parts: list
|
|
|
256
168
|
@pytest.mark.parametrize(
|
|
257
169
|
"input_dataset_parts",
|
|
258
170
|
[
|
|
259
|
-
pytest.param((None, Tag.input_dataset_parameters()), id="empty"),
|
|
260
171
|
pytest.param(
|
|
261
172
|
(input_dataset_parameters_part_factory(), Tag.input_dataset_parameters()),
|
|
262
173
|
id="single_param_no_date_no_file",
|
|
263
174
|
),
|
|
264
175
|
pytest.param(
|
|
265
176
|
(input_dataset_parameters_part_factory(has_file=True), Tag.input_dataset_parameters()),
|
|
266
|
-
id="
|
|
177
|
+
id="single_param_no_date_with_file",
|
|
267
178
|
),
|
|
268
179
|
pytest.param(
|
|
269
|
-
(
|
|
270
|
-
|
|
271
|
-
Tag.input_dataset_parameters(),
|
|
272
|
-
),
|
|
273
|
-
id="multi_param_no_date",
|
|
274
|
-
),
|
|
275
|
-
pytest.param(
|
|
276
|
-
(
|
|
277
|
-
input_dataset_parameters_part_factory(parameter_value_count=2, has_file=True),
|
|
278
|
-
Tag.input_dataset_parameters(),
|
|
279
|
-
),
|
|
280
|
-
id="multi_param_values_no_date",
|
|
180
|
+
(input_dataset_parameters_part_factory(has_date=True), Tag.input_dataset_parameters()),
|
|
181
|
+
id="single_param_with_date_no_file",
|
|
281
182
|
),
|
|
282
183
|
pytest.param(
|
|
283
184
|
(
|
|
284
185
|
input_dataset_parameters_part_factory(has_date=True, has_file=True),
|
|
285
186
|
Tag.input_dataset_parameters(),
|
|
286
187
|
),
|
|
287
|
-
id="
|
|
288
|
-
),
|
|
289
|
-
pytest.param(
|
|
290
|
-
(
|
|
291
|
-
input_dataset_parameters_part_factory(
|
|
292
|
-
parameter_count=2, has_date=True, has_file=True
|
|
293
|
-
),
|
|
294
|
-
Tag.input_dataset_parameters(),
|
|
295
|
-
),
|
|
296
|
-
id="multi_param_with_date",
|
|
297
|
-
),
|
|
298
|
-
],
|
|
299
|
-
)
|
|
300
|
-
def test_input_dataset_parameters(
|
|
301
|
-
task_with_input_dataset, input_dataset_parts: list[tuple[Any, str]]
|
|
302
|
-
):
|
|
303
|
-
"""
|
|
304
|
-
Given: a task with the InputDatasetMixin
|
|
305
|
-
When: getting the parameters in the input dataset
|
|
306
|
-
Then: the names of the parameters match the keys in the returned dictionary
|
|
307
|
-
"""
|
|
308
|
-
task = task_with_input_dataset
|
|
309
|
-
doc_part, _ = input_dataset_parts
|
|
310
|
-
doc_part = doc_part or [] # None case parsing of expected values
|
|
311
|
-
"""
|
|
312
|
-
expected_parameters is a dict with the parameter names as the keys
|
|
313
|
-
and the values are a list of value dicts for each parameter:
|
|
314
|
-
expected_parameters =
|
|
315
|
-
{ 'parameter_name_1': [param_dict_1, param_dict_2, ...],
|
|
316
|
-
'parameter_name_2': [param_dict_1, param_dict_2, ...],
|
|
317
|
-
...
|
|
318
|
-
}
|
|
319
|
-
where the param_dicts have the following format:
|
|
320
|
-
sample_param_dict =
|
|
321
|
-
{ "parameterValueId": <param_id>,
|
|
322
|
-
"parameterValue": <param_value>,
|
|
323
|
-
"parameterValueStartDate": <start_date>
|
|
324
|
-
}
|
|
325
|
-
"""
|
|
326
|
-
expected_parameters = dict()
|
|
327
|
-
for item in doc_part:
|
|
328
|
-
expected_parameters[item["parameterName"]] = item["parameterValues"]
|
|
329
|
-
create_parameter_files(task, expected_parameters)
|
|
330
|
-
# key is param name, values is list of InputDatasetParameterValue objects
|
|
331
|
-
for key, values in task.input_dataset_parameters.items():
|
|
332
|
-
assert key in expected_parameters
|
|
333
|
-
expected_values = expected_parameters[key]
|
|
334
|
-
# Iterate through multiple values if they exist
|
|
335
|
-
for value in values:
|
|
336
|
-
# Find the matching expected value for this value object
|
|
337
|
-
expected_value = [
|
|
338
|
-
item
|
|
339
|
-
for item in expected_values
|
|
340
|
-
if value.parameter_value_id == item["parameterValueId"]
|
|
341
|
-
]
|
|
342
|
-
# Make sure there's only one value
|
|
343
|
-
assert len(expected_value) == 1
|
|
344
|
-
# Now check the value
|
|
345
|
-
expected_value = expected_value[0]
|
|
346
|
-
assert value.parameter_value == json.loads(
|
|
347
|
-
expected_value["parameterValue"], object_hook=task._decode_parameter_value
|
|
348
|
-
)
|
|
349
|
-
expected_date = expected_value.get("parameterValueStartDate", datetime(1, 1, 1))
|
|
350
|
-
assert value.parameter_value_start_date == expected_date
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
@pytest.mark.parametrize(
|
|
354
|
-
"input_dataset_parts",
|
|
355
|
-
[
|
|
356
|
-
pytest.param((None, Tag.input_dataset_parameters()), id="empty"),
|
|
357
|
-
pytest.param(
|
|
358
|
-
(input_dataset_parameters_part_factory(), Tag.input_dataset_parameters()),
|
|
359
|
-
id="single_param_no_date_no_file",
|
|
360
|
-
),
|
|
361
|
-
pytest.param(
|
|
362
|
-
(input_dataset_parameters_part_factory(has_file=True), Tag.input_dataset_parameters()),
|
|
363
|
-
id="single_param_no_date",
|
|
188
|
+
id="single_param_with_date_with_file",
|
|
364
189
|
),
|
|
365
190
|
pytest.param(
|
|
366
191
|
(
|
|
367
|
-
input_dataset_parameters_part_factory(parameter_count=2
|
|
192
|
+
input_dataset_parameters_part_factory(parameter_count=2),
|
|
368
193
|
Tag.input_dataset_parameters(),
|
|
369
194
|
),
|
|
370
|
-
id="
|
|
195
|
+
id="multi_param_no_date_no_file",
|
|
371
196
|
),
|
|
372
197
|
pytest.param(
|
|
373
198
|
(
|
|
374
|
-
input_dataset_parameters_part_factory(
|
|
199
|
+
input_dataset_parameters_part_factory(parameter_count=2, has_date=True),
|
|
375
200
|
Tag.input_dataset_parameters(),
|
|
376
201
|
),
|
|
377
|
-
id="
|
|
202
|
+
id="multi_param_with_date_no_file",
|
|
378
203
|
),
|
|
379
204
|
pytest.param(
|
|
380
205
|
(
|
|
381
|
-
input_dataset_parameters_part_factory(
|
|
206
|
+
input_dataset_parameters_part_factory(parameter_count=2, has_file=True),
|
|
382
207
|
Tag.input_dataset_parameters(),
|
|
383
208
|
),
|
|
384
|
-
id="
|
|
209
|
+
id="multi_param_no_date_with_file",
|
|
385
210
|
),
|
|
386
211
|
pytest.param(
|
|
387
212
|
(
|
|
@@ -390,138 +215,30 @@ def test_input_dataset_parameters(
|
|
|
390
215
|
),
|
|
391
216
|
Tag.input_dataset_parameters(),
|
|
392
217
|
),
|
|
393
|
-
id="
|
|
394
|
-
),
|
|
395
|
-
],
|
|
396
|
-
)
|
|
397
|
-
def test_input_dataset_parameter_objects(
|
|
398
|
-
task_with_input_dataset, input_dataset_parts: list[tuple[Any, str]]
|
|
399
|
-
):
|
|
400
|
-
"""
|
|
401
|
-
Given: a task with the InputDatasetMixin
|
|
402
|
-
When: getting the parameters objects in the input dataset
|
|
403
|
-
Then: the InputDatsetObjects returned by the task method match the objects defined by the input
|
|
404
|
-
dataset doc part
|
|
405
|
-
"""
|
|
406
|
-
task = task_with_input_dataset
|
|
407
|
-
doc_part, _ = input_dataset_parts
|
|
408
|
-
doc_part = doc_part or [] # None case parsing of expected values
|
|
409
|
-
|
|
410
|
-
# Create a list of InputDatasetObjects from the input dataset doc part
|
|
411
|
-
expected_parameters = list()
|
|
412
|
-
for param_item in doc_part:
|
|
413
|
-
param_values_list = param_item["parameterValues"]
|
|
414
|
-
for param_value_dict in param_values_list:
|
|
415
|
-
if "__file__" in param_value_dict["parameterValue"]:
|
|
416
|
-
file_dict = json.loads(
|
|
417
|
-
param_value_dict["parameterValue"], object_hook=task._decode_parameter_value
|
|
418
|
-
)
|
|
419
|
-
expected_parameters.append(
|
|
420
|
-
InputDatasetObject(
|
|
421
|
-
bucket=file_dict["bucket"], object_key=file_dict["objectKey"]
|
|
422
|
-
)
|
|
423
|
-
)
|
|
424
|
-
# Check that each InputDatasetObject returned by the task is in the list of expected parameters
|
|
425
|
-
input_dataset_parameter_objects = task.input_dataset_parameter_objects
|
|
426
|
-
assert len(input_dataset_parameter_objects) == len(expected_parameters)
|
|
427
|
-
for input_dataset_object in input_dataset_parameter_objects:
|
|
428
|
-
assert input_dataset_object in expected_parameters
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
@pytest.mark.parametrize(
|
|
432
|
-
"input_parameter_dict",
|
|
433
|
-
[
|
|
434
|
-
{"bucket": "data", "objectKey": "parameters/805c46/714ff939158b4253859cde5e5d6f62c3.dat"},
|
|
435
|
-
{
|
|
436
|
-
"__file__": {
|
|
437
|
-
"bucket": "data",
|
|
438
|
-
"objectKey": "parameters/805c46/714ff939158b4253859cde5e5d6f62c3.dat",
|
|
439
|
-
}
|
|
440
|
-
},
|
|
441
|
-
{"key_name_1": "value_1", "key_name_2": "value_2", "key_name_3": "value_3"},
|
|
442
|
-
],
|
|
443
|
-
)
|
|
444
|
-
def test_convert_parameter_file_to_path(recipe_run_id, input_parameter_dict: dict):
|
|
445
|
-
"""
|
|
446
|
-
Given: a parameter value field to be json decoded
|
|
447
|
-
When: passing the parameter value string to the json decoder hook
|
|
448
|
-
Then: the hook passes non-file parameter strings without change and modifies file parameter strings
|
|
449
|
-
by replacing the __file__ dict in the value string with a bucket field, an objectKey field
|
|
450
|
-
and adds a param_path field and an is_file field
|
|
451
|
-
"""
|
|
452
|
-
# Initial test with no tags
|
|
453
|
-
with InputDatasetTask(
|
|
454
|
-
recipe_run_id=recipe_run_id,
|
|
455
|
-
workflow_name="workflow_name",
|
|
456
|
-
workflow_version="workflow_version",
|
|
457
|
-
) as task:
|
|
458
|
-
# Test with no tags...
|
|
459
|
-
input_dict = input_parameter_dict
|
|
460
|
-
output_dict = task._decode_parameter_value(input_dict)
|
|
461
|
-
if "__file__" not in input_dict:
|
|
462
|
-
assert input_dict == output_dict
|
|
463
|
-
else:
|
|
464
|
-
value_dict = input_dict["__file__"]
|
|
465
|
-
assert output_dict["bucket"] == value_dict["bucket"]
|
|
466
|
-
assert output_dict["objectKey"] == value_dict["objectKey"]
|
|
467
|
-
assert output_dict["is_file"]
|
|
468
|
-
assert output_dict["param_path"] is None
|
|
469
|
-
# Test with tags
|
|
470
|
-
if "__file__" not in input_dict:
|
|
471
|
-
output_dict = task._decode_parameter_value(input_dict)
|
|
472
|
-
assert input_dict == output_dict
|
|
473
|
-
else:
|
|
474
|
-
# Create the destination path
|
|
475
|
-
param_path = input_dict["__file__"]["objectKey"]
|
|
476
|
-
destination_path = task.scratch.absolute_path(param_path)
|
|
477
|
-
if not destination_path.parent.exists():
|
|
478
|
-
destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
479
|
-
destination_path.write_text(data="")
|
|
480
|
-
task.tag(path=destination_path, tags=Tag.parameter(destination_path.name))
|
|
481
|
-
output_dict = task._decode_parameter_value(input_dict)
|
|
482
|
-
value_dict = input_dict["__file__"]
|
|
483
|
-
assert output_dict["bucket"] == value_dict["bucket"]
|
|
484
|
-
assert output_dict["objectKey"] == value_dict["objectKey"]
|
|
485
|
-
assert output_dict["is_file"]
|
|
486
|
-
assert output_dict["param_path"] == destination_path
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
@pytest.mark.parametrize(
|
|
490
|
-
"input_dataset_parts",
|
|
491
|
-
[
|
|
492
|
-
pytest.param(
|
|
493
|
-
[
|
|
494
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_observe_frames()),
|
|
495
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_observe_frames()),
|
|
496
|
-
],
|
|
497
|
-
id="observe",
|
|
498
|
-
),
|
|
499
|
-
pytest.param(
|
|
500
|
-
[
|
|
501
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_calibration_frames()),
|
|
502
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_calibration_frames()),
|
|
503
|
-
],
|
|
504
|
-
id="calibration",
|
|
505
|
-
),
|
|
506
|
-
pytest.param(
|
|
507
|
-
[
|
|
508
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_parameters()),
|
|
509
|
-
(input_dataset_frames_part_factory(), Tag.input_dataset_parameters()),
|
|
510
|
-
],
|
|
511
|
-
id="params",
|
|
218
|
+
id="multi_param_with_date_with_file",
|
|
512
219
|
),
|
|
513
220
|
],
|
|
514
221
|
)
|
|
515
|
-
def
|
|
516
|
-
task_with_input_dataset, input_dataset_parts: list[tuple[Any, str]]
|
|
517
|
-
):
|
|
222
|
+
def test_input_dataset_parameters(task_with_input_dataset, input_dataset_parts: tuple[Any, str]):
|
|
518
223
|
"""
|
|
519
|
-
Given:
|
|
520
|
-
When:
|
|
521
|
-
Then:
|
|
224
|
+
Given: A task with an input dataset parameters part document written to file
|
|
225
|
+
When: Reading the file and validating into models
|
|
226
|
+
Then: The correct contents of the file, including file parameters, are loaded
|
|
522
227
|
"""
|
|
228
|
+
doc_part, tag = input_dataset_parts
|
|
523
229
|
task = task_with_input_dataset
|
|
524
|
-
|
|
525
|
-
task.
|
|
526
|
-
|
|
527
|
-
|
|
230
|
+
doc_from_file = next(
|
|
231
|
+
task.read(tags=tag, decoder=basemodel_decoder, model=InputDatasetPartDocumentList)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
params = [params.model_dump() for params in doc_from_file.doc_list]
|
|
235
|
+
assert params == doc_part
|
|
236
|
+
expected_files = []
|
|
237
|
+
for item in doc_part or []:
|
|
238
|
+
for val in item["parameterValues"]:
|
|
239
|
+
if "__file__" in val["parameterValue"]:
|
|
240
|
+
file_dict = json.loads(val["parameterValue"])
|
|
241
|
+
expected_files.append(file_dict["__file__"])
|
|
242
|
+
file_objects = sum([d.input_dataset_objects for d in doc_from_file.doc_list], [])
|
|
243
|
+
file_objects_dump = [f.model_dump() for f in file_objects]
|
|
244
|
+
assert file_objects_dump == expected_files
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Tests for the interservice bus mixin for a WorkflowDataTaskBase subclass"""
|
|
2
|
+
|
|
2
3
|
import logging
|
|
3
4
|
from typing import Dict
|
|
4
5
|
from typing import Type
|
|
@@ -15,7 +16,6 @@ from dkist_processing_common.config import common_configurations
|
|
|
15
16
|
from dkist_processing_common.models.message_queue_binding import common_message_queue_bindings
|
|
16
17
|
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
17
18
|
from dkist_processing_common.tasks.mixin.interservice_bus import InterserviceBusMixin
|
|
18
|
-
from dkist_processing_common.tests.conftest import recipe_run_id
|
|
19
19
|
|
|
20
20
|
logger = logging.getLogger(__name__)
|
|
21
21
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from dkist_processing_common.manual import ManualProcessing
|
|
4
|
+
from dkist_processing_common.tasks import WorkflowTaskBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ProvenanceTask(WorkflowTaskBase):
|
|
8
|
+
record_provenance = True
|
|
9
|
+
|
|
10
|
+
def run(self): ...
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@pytest.fixture(scope="function")
|
|
14
|
+
def manual_processing_run(tmp_path, recipe_run_id):
|
|
15
|
+
with ManualProcessing(
|
|
16
|
+
recipe_run_id=recipe_run_id,
|
|
17
|
+
workflow_path=tmp_path,
|
|
18
|
+
workflow_name="manual",
|
|
19
|
+
workflow_version="manual",
|
|
20
|
+
) as manual_processing_run:
|
|
21
|
+
yield manual_processing_run
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_manual_record_provenance(tmp_path, recipe_run_id, manual_processing_run):
|
|
25
|
+
"""
|
|
26
|
+
Given: A WorkflowTaskBase subclass with provenance recording turned on
|
|
27
|
+
When: Running the task with the ManualProcessing wrapper
|
|
28
|
+
Then: The provenance record exists on disk
|
|
29
|
+
"""
|
|
30
|
+
manual_processing_run.run_task(task=ProvenanceTask)
|
|
31
|
+
directory = tmp_path / str(recipe_run_id)
|
|
32
|
+
provenance_file = directory / "ProvenanceTask_provenance.json"
|
|
33
|
+
assert provenance_file.exists()
|
|
@@ -7,18 +7,16 @@ from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
|
7
7
|
from dkist_processing_common.models.tags import Tag
|
|
8
8
|
from dkist_processing_common.tasks.output_data_base import OutputDataBase
|
|
9
9
|
from dkist_processing_common.tasks.output_data_base import TransferDataBase
|
|
10
|
-
from dkist_processing_common.tests.conftest import FakeGQLClient
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
class OutputDataBaseTask(OutputDataBase):
|
|
14
|
-
def run(self) -> None:
|
|
15
|
-
...
|
|
13
|
+
def run(self) -> None: ...
|
|
16
14
|
|
|
17
15
|
|
|
18
16
|
@pytest.fixture
|
|
19
|
-
def output_data_base_task(recipe_run_id, mocker):
|
|
17
|
+
def output_data_base_task(recipe_run_id, mocker, fake_gql_client):
|
|
20
18
|
mocker.patch(
|
|
21
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
19
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
22
20
|
)
|
|
23
21
|
proposal_id = "test_proposal_id"
|
|
24
22
|
with OutputDataBaseTask(
|
|
@@ -37,9 +35,9 @@ class TransferDataTask(TransferDataBase):
|
|
|
37
35
|
|
|
38
36
|
|
|
39
37
|
@pytest.fixture
|
|
40
|
-
def transfer_data_task(recipe_run_id, tmp_path, mocker):
|
|
38
|
+
def transfer_data_task(recipe_run_id, tmp_path, mocker, fake_gql_client):
|
|
41
39
|
mocker.patch(
|
|
42
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
40
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
43
41
|
)
|
|
44
42
|
with TransferDataTask(
|
|
45
43
|
recipe_run_id=recipe_run_id,
|