diff --git a/flint/options.py b/flint/options.py index 6fee10d0..fb0ff80d 100644 --- a/flint/options.py +++ b/flint/options.py @@ -9,6 +9,10 @@ from pathlib import Path from typing import Collection, List, NamedTuple, Optional, Union +import yaml + +from flint.logging import logger + class BandpassOptions(NamedTuple): """Container that reoresents the flint related options that @@ -114,6 +118,41 @@ class FieldOptions(NamedTuple): """Rename MSs throught rounds of imaging and self-cal instead of creating copies. This will delete data-columns throughout. """ +def dump_field_options_to_yaml( + output_path: Path, field_options: FieldOptions, overwrite: bool = False +) -> Path: + """Dump the supplied instance of `FieldOptions` to a yaml file + for record keeping. + + The parent directory of the `output_path` will be created if it + does not already exist. + + Args: + output_path (Path): Path of the output file. + field_options (FieldOptions): The `FieldOptions` class to write. + overwrite (bool, optional): Overwrite the file if it exists. Defaults to False. + + Raises: + FileExistsError: Raise if `output_path` already exists and `overwrite` is `False` + + Returns: + Path: Output path written to. + """ + + logger.info(f"Writing field_options to {output_path}") + + if not overwrite and output_path.exists(): + raise FileExistsError(f"{output_path=} exists. ") + + # Create the directory just in case + output_path.parent.mkdir(parents=True, exist_ok=True) + + with open(output_path, "w") as out_file: + yaml.dump(data=field_options, stream=out_file, sort_keys=False) + + return output_path + + # TODO: Perhaps move these to flint.naming, and can be built up # based on rules, e.g. imager used, source finder etc. DEFAULT_TAR_RE_PATTERNS = ( diff --git a/flint/prefect/flows/continuum_pipeline.py b/flint/prefect/flows/continuum_pipeline.py index 1a52493e..78e5c5e4 100644 --- a/flint/prefect/flows/continuum_pipeline.py +++ b/flint/prefect/flows/continuum_pipeline.py @@ -23,10 +23,11 @@ from flint.ms import find_mss from flint.naming import ( CASDANameComponents, + add_timestamp_to_path, extract_components_from_name, get_sbid_from_path, ) -from flint.options import FieldOptions +from flint.options import FieldOptions, dump_field_options_to_yaml from flint.prefect.clusters import get_dask_runner from flint.prefect.common.imaging import ( _create_convol_linmos_images, @@ -153,6 +154,13 @@ def process_science_fields( science_path=science_path, split_path=split_path, check_exists=True ) + dump_field_options_to_yaml( + output_path=add_timestamp_to_path( + input_path=output_split_science_path / "field_options.yaml" + ), + field_optios=field_options, + ) + archive_wait_for: List[Any] = [] strategy = _load_and_copy_strategy( diff --git a/tests/test_options.py b/tests/test_options.py index d55c2fbf..982f8649 100644 --- a/tests/test_options.py +++ b/tests/test_options.py @@ -5,10 +5,35 @@ from pathlib import Path -from flint.options import FieldOptions +import pytest + +from flint.options import FieldOptions, dump_field_options_to_yaml from flint.prefect.flows.continuum_pipeline import get_parser +def test_dump_field_options_to_yaml(tmpdir): + """See if the field options file can be dumped to an output directory""" + tmpdir = Path(tmpdir) + + field_options = FieldOptions( + flagger_container=Path("a"), calibrate_container=Path("b") + ) + + assert not (tmpdir / "Jack").exists() + + path_1 = tmpdir / "field_options.yaml" + path_2 = tmpdir / "Jack" / "Sparrow" / "field_options.yaml" + + for path in (path_1, path_2): + output_path = dump_field_options_to_yaml( + output_path=path, field_options=field_options + ) + assert output_path.exists() + + with pytest.raises(FileExistsError): + dump_field_options_to_yaml(output_path=path_2, field_options=field_options) + + def test_config_field_options(tmpdir): output_file = f"{tmpdir}/example.config" contents = """--holofile /scratch3/projects/spiceracs/RACS_Low2_Holography/akpb.iquv.square_6x6.63.887MHz.SB39549.cube.fits