Skip to content

Commit

Permalink
Merge pull request #780 from astronomerritt/configs_command
Browse files Browse the repository at this point in the history
Adding command to copy config files.
  • Loading branch information
mschwamb authored Feb 6, 2024
2 parents a25d1b1 + 7da2ec6 commit 6823cff
Show file tree
Hide file tree
Showing 3 changed files with 229 additions and 0 deletions.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ sorcha = "sorcha.sorcha:main"
makeSLURMscript = "sorcha.utilities.makeSLURMscript:main"
createResultsSQLDatabase = "sorcha.utilities.createResultsSQLDatabase:main"
bootstrap_sorcha_data_files = "sorcha.utilities.retrieve_ephemeris_data_files:main"
sorcha_copy_configs = "sorcha.utilities.sorcha_copy_configs:main"

[project.urls]
"Documentation" = "https://sorcha.readthedocs.io/en/latest/"
Expand Down
150 changes: 150 additions & 0 deletions src/sorcha/utilities/sorcha_copy_configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import os
import argparse
from pathlib import Path
import shutil
import sys

from sorcha.modules.PPConfigParser import PPFindDirectoryOrExit


def copy_demo_configs(copy_location, which_configs, force_overwrite):
"""
Copies the example Sorcha configuration files to a user-specified location.
Parameters
-----------
copy_location : string
String containing the filepath of the location to which the configuration files should be copied.
which_configs : string
String indicating which configuration files to retrieve. Should be "rubin", "demo" or "all".
force_overwrite: boolean
Flag for determining whether existing files should be overwritten.
Returns
-----------
None
"""

_ = PPFindDirectoryOrExit(copy_location, "filepath")

path_to_file = os.path.abspath(__file__)

path_to_surveys = os.path.join(str(Path(path_to_file).parents[3]), "survey_setups")
path_to_demo = os.path.join(str(Path(path_to_file).parents[3]), "demo")

if which_configs == "rubin_circle":
config_locations = [os.path.join(path_to_surveys, "Rubin_circular_approximation.ini")]
elif which_configs == "rubin_footprint":
config_locations = [os.path.join(path_to_surveys, "Rubin_full_footprint.ini")]
elif which_configs == "all":
config_locations = [
os.path.join(path_to_surveys, "Rubin_circular_approximation.ini"),
os.path.join(path_to_surveys, "Rubin_full_footprint.ini"),
]
else:
sys.exit(
"String '{}' not recognised for 'configs' variable. Must be 'rubin_circle', 'rubin_footprint' or 'all'.".format(
which_configs
)
)

for config in config_locations:
if not force_overwrite and os.path.isfile(config):
sys.exit("Identical file exists at location. Re-run with -f or --force to force overwrite.")

shutil.copy(config, copy_location)

print("Example configuration files {} copied to {}.".format(config_locations, copy_location))


def parse_file_selection(file_select):
"""Turns the number entered by the user at the command line into a string
prompt. Also performs error handling.
Parameters
-----------
file_select : int
Integer entered by the user at command line.
Returns
-----------
which_configs : string
String indicating which configuration files to retrieve. Should be "rubin", "demo" or "all".
"""

try:
file_select = int(file_select)
except ValueError:
sys.exit("Input could not be converted to a valid integer. Please try again.")

if file_select not in [1, 2, 3]:
sys.exit("Input could not be converted to a valid integer. Please input an integer between 1 and 3.")

selection_dict = {1: "rubin_circle", 2: "rubin_footprint", 3: "all"}

which_configs = selection_dict[file_select]

return which_configs


def main():
"""
Copies example configuration files for Sorcha from the installation location
to a user-specified location. Filepath to copy files to is specified by command-line
flag. Selection of configuration files is done via user input.
usage: sorcha_copy_configs [-h] [-p PATH]
arguments:
-h, --help Show this help message and exit.
[-p PATH, --path PATH] Filepath where you want to copy the config files. Default is current working directory.
Parameters
-----------
None
Returns
-----------
None
"""

parser = argparse.ArgumentParser(
description="Copies example Sorcha configuration files to a user-specified location."
)

parser.add_argument(
"-p",
"--path",
help="Filepath where you want to copy the config files. Default is current working directory.",
type=str,
default="./",
)

parser.add_argument(
"-f",
"--force",
help="Force deletion/overwrite of existing config file(s). Default False.",
action="store_true",
default=False,
)

args = parser.parse_args()

print("\nWhich configuration file(s) would you like to copy?:\n")
print("1. Rubin-specific configuration file using circular approximation of camera footprint (faster).\n")
print("2. Rubin-specific configuration file using full camera footprint (slower, but more accurate).\n")
print("3. All.\n")
file_select = input("Please enter a number and hit Return/Enter.\n")

which_configs = parse_file_selection(file_select)

copy_location = os.path.abspath(args.path)
copy_demo_configs(copy_location, which_configs, args.force)


if __name__ == "__main__":
main()
78 changes: 78 additions & 0 deletions tests/sorcha/test_sorcha_copy_configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
import pytest


def test_sorcha_copy_configs(tmp_path):
from sorcha.utilities.sorcha_copy_configs import copy_demo_configs

# test that the Rubin files are successfully copied
copy_demo_configs(tmp_path, "rubin_circle", True)

assert os.path.isfile(os.path.join(tmp_path, "Rubin_circular_approximation.ini"))

copy_demo_configs(tmp_path, "rubin_footprint", True)

assert os.path.isfile(os.path.join(tmp_path, "Rubin_full_footprint.ini"))

# remove those files
os.remove(os.path.join(tmp_path, "Rubin_circular_approximation.ini"))
os.remove(os.path.join(tmp_path, "Rubin_full_footprint.ini"))

# test that all the configs are successfully copied
copy_demo_configs(tmp_path, "all", True)

assert os.path.isfile(os.path.join(tmp_path, "Rubin_circular_approximation.ini"))
assert os.path.isfile(os.path.join(tmp_path, "Rubin_full_footprint.ini"))

# test the error message if user supplies non-existent directory
dummy_folder = os.path.join(tmp_path, "dummy_folder")
with pytest.raises(SystemExit) as e:
copy_demo_configs(dummy_folder, "all", True)

assert e.value.code == "ERROR: filepath {} supplied for filepath argument does not exist.".format(
dummy_folder
)

# test the error message if user supplies unrecognised keyword for which_configs variable
with pytest.raises(SystemExit) as e2:
copy_demo_configs(tmp_path, "laphroaig", True)

assert (
e2.value.code
== "String 'laphroaig' not recognised for 'configs' variable. Must be 'rubin_circle', 'rubin_footprint' or 'all'."
)

# test tthe error message if file exists and overwrite isn't forced

with pytest.raises(SystemExit) as e3:
copy_demo_configs(tmp_path, "rubin_footprint", False)

assert e3.value.code == "Identical file exists at location. Re-run with -f or --force to force overwrite."


def test_parse_file_selection():
from sorcha.utilities.sorcha_copy_configs import parse_file_selection

# test to make sure the inputs align with the correct options
test_rubin_circle = parse_file_selection("1")
test_rubin_footprint = parse_file_selection("2")
test_all = parse_file_selection("3")

assert test_rubin_circle == "rubin_circle"
assert test_rubin_footprint == "rubin_footprint"
assert test_all == "all"

# test error messages

with pytest.raises(SystemExit) as e:
test_string = parse_file_selection("not_an_integer")

assert e.value.code == "Input could not be converted to a valid integer. Please try again."

with pytest.raises(SystemExit) as e2:
test_wrong_integer = parse_file_selection("4")

assert (
e2.value.code
== "Input could not be converted to a valid integer. Please input an integer between 1 and 3."
)

0 comments on commit 6823cff

Please sign in to comment.