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
|
@@ -5,7 +5,6 @@ import pytest
|
|
|
5
5
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
6
6
|
from dkist_processing_common.models.tags import Tag
|
|
7
7
|
from dkist_processing_common.tasks import TransferL1Data
|
|
8
|
-
from dkist_processing_common.tests.conftest import FakeGQLClient
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
def fake_list_objects(self, bucket, prefix=None):
|
|
@@ -37,7 +36,7 @@ def transfer_l1_data_task(recipe_run_id, tmp_path, fake_constants_db):
|
|
|
37
36
|
task._purge()
|
|
38
37
|
|
|
39
38
|
|
|
40
|
-
def test_transfer_l1_data(transfer_l1_data_task, mocker):
|
|
39
|
+
def test_transfer_l1_data(transfer_l1_data_task, mocker, fake_gql_client):
|
|
41
40
|
"""
|
|
42
41
|
Given: A task with frames and movies tagged as output
|
|
43
42
|
When: Transfering the L1 data
|
|
@@ -45,7 +44,7 @@ def test_transfer_l1_data(transfer_l1_data_task, mocker):
|
|
|
45
44
|
"""
|
|
46
45
|
# Yeah, we mock a whole bunch of stuff here, but this test at least confirms that the setup to these calls is correct
|
|
47
46
|
mocker.patch(
|
|
48
|
-
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=
|
|
47
|
+
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient", new=fake_gql_client
|
|
49
48
|
)
|
|
50
49
|
mocker.patch(
|
|
51
50
|
"dkist_processing_common.tasks.mixin.globus.GlobusMixin.globus_transfer_scratch_to_object_store"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"""Tests for the tasks.trial_catalog module."""
|
|
2
|
+
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
from string import ascii_uppercase
|
|
4
5
|
from uuid import uuid4
|
|
@@ -7,19 +8,34 @@ import astropy.units as u
|
|
|
7
8
|
import pytest
|
|
8
9
|
from astropy.io import fits
|
|
9
10
|
from dkist_data_simulator.spec214.vbi import SimpleVBIDataset
|
|
10
|
-
from
|
|
11
|
+
from sqids import Sqids
|
|
11
12
|
|
|
12
13
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
13
14
|
from dkist_processing_common.codecs.asdf import asdf_decoder
|
|
15
|
+
from dkist_processing_common.codecs.basemodel import basemodel_encoder
|
|
14
16
|
from dkist_processing_common.codecs.bytes import bytes_decoder
|
|
15
17
|
from dkist_processing_common.codecs.fits import fits_hdulist_encoder
|
|
16
18
|
from dkist_processing_common.codecs.json import json_decoder
|
|
17
19
|
from dkist_processing_common.codecs.quality import quality_data_encoder
|
|
20
|
+
from dkist_processing_common.models.input_dataset import InputDatasetParameter
|
|
21
|
+
from dkist_processing_common.models.input_dataset import InputDatasetPartDocumentList
|
|
18
22
|
from dkist_processing_common.models.tags import Tag
|
|
19
23
|
from dkist_processing_common.tasks import CreateTrialAsdf
|
|
20
24
|
from dkist_processing_common.tasks import CreateTrialDatasetInventory
|
|
21
25
|
from dkist_processing_common.tasks import CreateTrialQualityReport
|
|
22
|
-
from dkist_processing_common.tests.
|
|
26
|
+
from dkist_processing_common.tests.mock_metadata_store import input_dataset_parameters_part_factory
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@pytest.fixture()
|
|
30
|
+
def mock_input_dataset_parts() -> InputDatasetPartDocumentList:
|
|
31
|
+
"""An InputDatasetPartDocumentList with two parameters, each with one value and a date."""
|
|
32
|
+
raw = input_dataset_parameters_part_factory(
|
|
33
|
+
parameter_count=2,
|
|
34
|
+
parameter_value_count=1,
|
|
35
|
+
has_date=True,
|
|
36
|
+
has_file=False,
|
|
37
|
+
)
|
|
38
|
+
return InputDatasetPartDocumentList.model_validate({"doc_list": raw})
|
|
23
39
|
|
|
24
40
|
|
|
25
41
|
@pytest.fixture()
|
|
@@ -41,17 +57,40 @@ def scratch_with_l1_frames(recipe_run_id, tmp_path) -> WorkflowFileSystem:
|
|
|
41
57
|
scratch.write(
|
|
42
58
|
file_obj, tags=[Tag.output(), Tag.frame()], relative_path=f"{uuid4().hex}.dat"
|
|
43
59
|
)
|
|
60
|
+
|
|
61
|
+
return scratch
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.fixture()
|
|
65
|
+
def scratch_with_l1_frames_and_parameters(
|
|
66
|
+
scratch_with_l1_frames, mock_input_dataset_parts
|
|
67
|
+
) -> WorkflowFileSystem:
|
|
68
|
+
"""Scratch instance for a recipe run id with tagged L1 frames and input parameters."""
|
|
69
|
+
scratch = scratch_with_l1_frames
|
|
70
|
+
|
|
71
|
+
# Write validated Pydantic model bytes expected by InputDatasetPartDocumentList
|
|
72
|
+
file_obj = basemodel_encoder(mock_input_dataset_parts)
|
|
73
|
+
scratch.write(
|
|
74
|
+
file_obj,
|
|
75
|
+
tags=Tag.input_dataset_parameters(),
|
|
76
|
+
relative_path=f"{uuid4().hex}.json",
|
|
77
|
+
)
|
|
44
78
|
return scratch
|
|
45
79
|
|
|
46
80
|
|
|
47
81
|
@pytest.fixture()
|
|
48
82
|
def create_trial_dataset_inventory_task(
|
|
49
|
-
recipe_run_id,
|
|
83
|
+
recipe_run_id,
|
|
84
|
+
tmp_path,
|
|
85
|
+
scratch_with_l1_frames,
|
|
86
|
+
fake_constants_db,
|
|
87
|
+
mocker,
|
|
88
|
+
fake_gql_client,
|
|
50
89
|
) -> CreateTrialDatasetInventory:
|
|
51
90
|
"""An instance of CreateTrialDatasetInventory with L1 frames tagged in scratch."""
|
|
52
91
|
mocker.patch(
|
|
53
92
|
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient",
|
|
54
|
-
new=
|
|
93
|
+
new=fake_gql_client,
|
|
55
94
|
)
|
|
56
95
|
task = CreateTrialDatasetInventory(
|
|
57
96
|
recipe_run_id=recipe_run_id,
|
|
@@ -80,6 +119,22 @@ def create_trial_asdf_task(
|
|
|
80
119
|
task._purge()
|
|
81
120
|
|
|
82
121
|
|
|
122
|
+
@pytest.fixture(scope="function")
|
|
123
|
+
def create_trial_asdf_task_with_params(
|
|
124
|
+
recipe_run_id, tmp_path, scratch_with_l1_frames_and_parameters, fake_constants_db
|
|
125
|
+
) -> CreateTrialAsdf:
|
|
126
|
+
"""An instance of CreateTrialAsdf with L1 frames and input parameters tagged in scratch."""
|
|
127
|
+
task = CreateTrialAsdf(
|
|
128
|
+
recipe_run_id=recipe_run_id,
|
|
129
|
+
workflow_name="trial_asdf",
|
|
130
|
+
workflow_version="trial_asdf_version",
|
|
131
|
+
)
|
|
132
|
+
task.scratch = scratch_with_l1_frames_and_parameters
|
|
133
|
+
task.constants._update(fake_constants_db)
|
|
134
|
+
yield task
|
|
135
|
+
task._purge()
|
|
136
|
+
|
|
137
|
+
|
|
83
138
|
@pytest.fixture()
|
|
84
139
|
def create_trial_quality_report_task(
|
|
85
140
|
recipe_run_id, tmp_path, fake_constants_db
|
|
@@ -138,25 +193,32 @@ def test_create_trial_dataset_inventory(create_trial_dataset_inventory_task):
|
|
|
138
193
|
assert len(inventory) > 20 # a bunch
|
|
139
194
|
|
|
140
195
|
|
|
141
|
-
|
|
196
|
+
@pytest.mark.parametrize("with_params", [False, True], ids=["no_params", "with_params"])
|
|
197
|
+
def test_create_trial_asdf(with_params, request, recipe_run_id, mock_input_dataset_parts):
|
|
142
198
|
"""
|
|
143
199
|
:Given: An instance of CreateTrialAsdf with L1 frames tagged in scratch
|
|
144
200
|
:When: CreateTrialAsdf is run
|
|
145
201
|
:Then: An asdf file for the dataset is tagged in scratch
|
|
146
202
|
"""
|
|
147
|
-
task =
|
|
203
|
+
task = request.getfixturevalue(
|
|
204
|
+
"create_trial_asdf_task_with_params" if with_params else "create_trial_asdf_task"
|
|
205
|
+
)
|
|
148
206
|
# When
|
|
149
207
|
task()
|
|
208
|
+
|
|
150
209
|
# Then
|
|
151
210
|
asdf_tags = [Tag.output(), Tag.asdf()]
|
|
152
211
|
filepaths = list(task.scratch.find_all(tags=asdf_tags))
|
|
153
212
|
assert len(filepaths) == 1
|
|
154
|
-
dataset_id =
|
|
155
|
-
assert filepaths[0].name == f"INSTRUMENT_L1_20240416T160000_{dataset_id}
|
|
213
|
+
dataset_id = Sqids(min_length=6, alphabet=ascii_uppercase).encode([recipe_run_id])
|
|
214
|
+
assert filepaths[0].name == f"INSTRUMENT_L1_20240416T160000_{dataset_id}_metadata.asdf"
|
|
215
|
+
|
|
156
216
|
results = list(task.read(tags=asdf_tags, decoder=asdf_decoder))
|
|
157
217
|
assert len(results) == 1
|
|
218
|
+
|
|
158
219
|
tree = results[0]
|
|
159
220
|
assert isinstance(tree, dict)
|
|
221
|
+
|
|
160
222
|
for file_name in tree["dataset"].files.filenames:
|
|
161
223
|
# This is a slightly better than check that `not Path(file_name).is_absolute()` because it confirms
|
|
162
224
|
# we've correctly stripped the path of *all* parents (not just those that start at root).
|
|
@@ -164,6 +226,19 @@ def test_create_trial_asdf(create_trial_asdf_task, recipe_run_id):
|
|
|
164
226
|
# `scratch.workflow_base_path`
|
|
165
227
|
assert Path(file_name).name == file_name
|
|
166
228
|
|
|
229
|
+
# Only check parameters when present
|
|
230
|
+
ds = tree["dataset"]
|
|
231
|
+
assert "parameters" in ds.meta
|
|
232
|
+
parameters = ds.meta["parameters"]
|
|
233
|
+
assert isinstance(parameters, list)
|
|
234
|
+
if with_params:
|
|
235
|
+
assert parameters, f"ASDF tree must include input parameters: {parameters}"
|
|
236
|
+
assert len(parameters) == len(mock_input_dataset_parts.doc_list)
|
|
237
|
+
for param in parameters:
|
|
238
|
+
assert InputDatasetParameter.model_validate(param) in mock_input_dataset_parts.doc_list
|
|
239
|
+
else:
|
|
240
|
+
assert ds.meta["parameters"] == []
|
|
241
|
+
|
|
167
242
|
|
|
168
243
|
def test_create_trial_quality_report(create_trial_quality_report_task):
|
|
169
244
|
"""
|
|
@@ -6,11 +6,13 @@ import pytest
|
|
|
6
6
|
from pydantic.dataclasses import dataclass as validating_dataclass
|
|
7
7
|
|
|
8
8
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
9
|
-
from dkist_processing_common.models.graphql import
|
|
9
|
+
from dkist_processing_common.models.graphql import RecipeRunConfiguration
|
|
10
10
|
from dkist_processing_common.models.tags import Tag
|
|
11
11
|
from dkist_processing_common.tasks.mixin.globus import GlobusTransferItem
|
|
12
12
|
from dkist_processing_common.tasks.trial_output_data import TransferTrialData
|
|
13
|
-
from dkist_processing_common.tests.
|
|
13
|
+
from dkist_processing_common.tests.mock_metadata_store import RecipeRunResponseMapping
|
|
14
|
+
from dkist_processing_common.tests.mock_metadata_store import fake_gql_client_factory
|
|
15
|
+
from dkist_processing_common.tests.mock_metadata_store import make_default_recipe_run_response
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
@pytest.fixture
|
|
@@ -19,48 +21,46 @@ def destination_bucket() -> str:
|
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
@pytest.fixture
|
|
22
|
-
def
|
|
24
|
+
def fake_gql_client_recipe_run_configuration(
|
|
23
25
|
custom_root_name,
|
|
24
26
|
custom_dir_name,
|
|
25
27
|
destination_bucket,
|
|
26
28
|
):
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return GQLClientWithConfiguration
|
|
29
|
+
recipe_run_response = make_default_recipe_run_response()
|
|
30
|
+
configuration = RecipeRunConfiguration(
|
|
31
|
+
trial_root_directory_name=custom_root_name,
|
|
32
|
+
trial_directory_name=custom_dir_name,
|
|
33
|
+
destination_bucket=destination_bucket,
|
|
34
|
+
)
|
|
35
|
+
recipe_run_response.configuration = configuration.model_dump_json()
|
|
36
|
+
|
|
37
|
+
new_response_mapping = RecipeRunResponseMapping(response=recipe_run_response)
|
|
38
|
+
FakeGQLClientWithConfiguration = fake_gql_client_factory(
|
|
39
|
+
response_mapping_override=new_response_mapping
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
return FakeGQLClientWithConfiguration
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
@pytest.fixture
|
|
45
|
-
def
|
|
46
|
+
def fake_gql_client_recipe_run_configuration_with_tag_lists(
|
|
46
47
|
custom_root_name, custom_dir_name, destination_bucket, exclusive_tag_lists
|
|
47
48
|
):
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return GQLClientWithConfiguration
|
|
49
|
+
recipe_run_response = make_default_recipe_run_response()
|
|
50
|
+
configuration = RecipeRunConfiguration(
|
|
51
|
+
trial_root_directory_name=custom_root_name,
|
|
52
|
+
trial_directory_name=custom_dir_name,
|
|
53
|
+
destination_bucket=destination_bucket,
|
|
54
|
+
trial_exclusive_transfer_tag_lists=exclusive_tag_lists,
|
|
55
|
+
)
|
|
56
|
+
recipe_run_response.configuration = configuration.model_dump_json()
|
|
57
|
+
|
|
58
|
+
new_response_mapping = RecipeRunResponseMapping(response=recipe_run_response)
|
|
59
|
+
FakeGQLClientWithConfiguration = fake_gql_client_factory(
|
|
60
|
+
response_mapping_override=new_response_mapping
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return FakeGQLClientWithConfiguration
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
@pytest.fixture
|
|
@@ -70,11 +70,11 @@ def trial_output_task() -> type[TransferTrialData]:
|
|
|
70
70
|
|
|
71
71
|
@pytest.fixture
|
|
72
72
|
def basic_trial_output_task(
|
|
73
|
-
recipe_run_id,
|
|
73
|
+
recipe_run_id, fake_gql_client_recipe_run_configuration, trial_output_task, tmp_path, mocker
|
|
74
74
|
):
|
|
75
75
|
mocker.patch(
|
|
76
76
|
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient",
|
|
77
|
-
new=
|
|
77
|
+
new=fake_gql_client_recipe_run_configuration,
|
|
78
78
|
)
|
|
79
79
|
proposal_id = "test_proposal_id"
|
|
80
80
|
with trial_output_task(
|
|
@@ -121,10 +121,10 @@ class OutputFileNames:
|
|
|
121
121
|
def complete_trial_output_task(
|
|
122
122
|
request, recipe_run_id, trial_output_task, tmp_path, mocker
|
|
123
123
|
) -> tuple[TransferTrialData, str, OutputFileObjects]:
|
|
124
|
-
|
|
124
|
+
fake_gql_client = request.param
|
|
125
125
|
mocker.patch(
|
|
126
126
|
"dkist_processing_common.tasks.mixin.metadata_store.GraphQLClient",
|
|
127
|
-
new=request.getfixturevalue(
|
|
127
|
+
new=request.getfixturevalue(fake_gql_client),
|
|
128
128
|
)
|
|
129
129
|
proposal_id = "test_proposal_id"
|
|
130
130
|
with trial_output_task(
|
|
@@ -158,13 +158,12 @@ def complete_trial_output_task(
|
|
|
158
158
|
task.write(asdf_file_obj, relative_path=asdf_file_name, tags=[Tag.output(), Tag.asdf()])
|
|
159
159
|
|
|
160
160
|
# Write quality data
|
|
161
|
-
# quality data is not tagged as OUTPUT
|
|
162
161
|
quality_data_obj = uuid4().hex.encode("utf8")
|
|
163
162
|
quality_data_name = "quality_data.json"
|
|
164
163
|
task.write(
|
|
165
164
|
quality_data_obj,
|
|
166
165
|
relative_path=quality_data_name,
|
|
167
|
-
tags=Tag.quality_data(),
|
|
166
|
+
tags=[Tag.output(), Tag.quality_data()],
|
|
168
167
|
)
|
|
169
168
|
|
|
170
169
|
# Write a quality report file
|
|
@@ -241,7 +240,9 @@ def test_format_object_key(
|
|
|
241
240
|
)
|
|
242
241
|
|
|
243
242
|
|
|
244
|
-
@pytest.mark.parametrize(
|
|
243
|
+
@pytest.mark.parametrize(
|
|
244
|
+
"complete_trial_output_task", ["fake_gql_client_recipe_run_configuration"], indirect=True
|
|
245
|
+
)
|
|
245
246
|
@pytest.mark.parametrize(
|
|
246
247
|
"custom_root_name, custom_dir_name",
|
|
247
248
|
[
|
|
@@ -289,7 +290,9 @@ def test_build_transfer_list(
|
|
|
289
290
|
|
|
290
291
|
|
|
291
292
|
@pytest.mark.parametrize(
|
|
292
|
-
"complete_trial_output_task",
|
|
293
|
+
"complete_trial_output_task",
|
|
294
|
+
["fake_gql_client_recipe_run_configuration_with_tag_lists"],
|
|
295
|
+
indirect=True,
|
|
293
296
|
)
|
|
294
297
|
@pytest.mark.parametrize(
|
|
295
298
|
"custom_root_name, custom_dir_name, exclusive_tag_lists, expected_output",
|
|
@@ -332,33 +335,3 @@ def test_build_transfer_list_with_exclusive_tag_lists(
|
|
|
332
335
|
assert transfer_item.destination_path == expected_destination_path
|
|
333
336
|
with transfer_item.source_path.open(mode="rb") as f:
|
|
334
337
|
assert file_obj == f.read()
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
@pytest.mark.parametrize(
|
|
338
|
-
"complete_trial_output_task", ["recipe_run_configuration_with_tag_lists"], indirect=True
|
|
339
|
-
)
|
|
340
|
-
@pytest.mark.parametrize(
|
|
341
|
-
"custom_root_name, custom_dir_name, exclusive_tag_lists",
|
|
342
|
-
[
|
|
343
|
-
pytest.param(
|
|
344
|
-
None, None, [Tag.task("TASKY_MCTASKERSON")], id="Default trial dir and trial root names"
|
|
345
|
-
)
|
|
346
|
-
],
|
|
347
|
-
)
|
|
348
|
-
def test_build_transfer_list_with_bad_exclusive_tag_lists(
|
|
349
|
-
complete_trial_output_task,
|
|
350
|
-
destination_bucket,
|
|
351
|
-
custom_dir_name,
|
|
352
|
-
custom_root_name,
|
|
353
|
-
exclusive_tag_lists,
|
|
354
|
-
):
|
|
355
|
-
"""
|
|
356
|
-
:Given: A Task based on TrialTransferDataBase
|
|
357
|
-
:When: The exclusive tag list is a simple list instead of the required list of lists
|
|
358
|
-
:Then: The correct value error is raised
|
|
359
|
-
"""
|
|
360
|
-
task, proposal_id, output_file_objects, output_file_names = complete_trial_output_task
|
|
361
|
-
|
|
362
|
-
with pytest.raises(ValueError) as ve:
|
|
363
|
-
transfer_list = task.build_transfer_list()
|
|
364
|
-
assert f"tag_lists={exclusive_tag_lists} must" in str(ve)
|
|
@@ -2,13 +2,12 @@ import json
|
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
4
|
import tomllib
|
|
5
|
-
from
|
|
5
|
+
from importlib.metadata import version
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from string import ascii_uppercase
|
|
8
8
|
|
|
9
9
|
import pytest
|
|
10
|
-
from
|
|
11
|
-
from pkg_resources import get_distribution
|
|
10
|
+
from sqids import Sqids
|
|
12
11
|
|
|
13
12
|
import dkist_processing_common
|
|
14
13
|
from dkist_processing_common._util.scratch import WorkflowFileSystem
|
|
@@ -183,16 +182,15 @@ def test_dataset_id(workflow_data_task):
|
|
|
183
182
|
Then: the dataset id hashed from the recipe run id is returned
|
|
184
183
|
"""
|
|
185
184
|
task = workflow_data_task[0]
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
expected_dataset_id = Sqids(min_length=6, alphabet=ascii_uppercase).encode([task.recipe_run_id])
|
|
186
|
+
assert len(expected_dataset_id) >= 6
|
|
187
|
+
assert task.constants.dataset_id == expected_dataset_id
|
|
189
188
|
|
|
190
189
|
|
|
191
190
|
class ProvenanceTask(WorkflowTaskBase):
|
|
192
191
|
record_provenance = True
|
|
193
192
|
|
|
194
|
-
def run(self):
|
|
195
|
-
...
|
|
193
|
+
def run(self): ...
|
|
196
194
|
|
|
197
195
|
# Because I couldn't figure out how to mock the mixin
|
|
198
196
|
def metadata_store_record_provenance(self, is_task_manual: bool, library_versions: str):
|
|
@@ -204,7 +202,7 @@ class ProvenanceTask(WorkflowTaskBase):
|
|
|
204
202
|
libraryVersions=library_versions,
|
|
205
203
|
workflowVersion=self.workflow_version,
|
|
206
204
|
)
|
|
207
|
-
self.write(data=bytes(
|
|
205
|
+
self.write(data=bytes(params.model_dump_json(), "utf-8"), tags=["TEST_PROVENANCE"])
|
|
208
206
|
|
|
209
207
|
|
|
210
208
|
@pytest.fixture(scope="function")
|
|
@@ -272,7 +270,7 @@ def test_library_versions(provenance_task, package_dependencies):
|
|
|
272
270
|
# installed packages.
|
|
273
271
|
for package in package_dependencies:
|
|
274
272
|
assert package in libraries
|
|
275
|
-
assert libraries[package] ==
|
|
273
|
+
assert libraries[package] == version(package)
|
|
276
274
|
|
|
277
275
|
|
|
278
276
|
def test_record_provenance(provenance_task):
|