From eaab8f9969da099a20474067d0d6d3fada7ed60a Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:35:46 -0400 Subject: [PATCH 1/8] refactor looper init tutorial and add some color to terminal using rich --- looper/cli_pydantic.py | 35 +++++++++---- looper/utils.py | 95 ++++++++++++++++++++++++++++++++++++ looper_init.py | 68 -------------------------- tests/smoketests/test_run.py | 2 +- 4 files changed, 121 insertions(+), 79 deletions(-) delete mode 100644 looper_init.py diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index 954bdef60..a9b762c3d 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -53,10 +53,11 @@ init_generic_pipeline, read_yaml_file, inspect_looper_config_file, - is_PEP_file_type, + is_PEP_file_type, looper_config_tutorial, ) from typing import List, Tuple +from rich.console import Console def opt_attr_pair(name: str) -> Tuple[str, str]: @@ -122,16 +123,30 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): sys.exit(1) if subcommand_name == "init": - return int( - not initiate_looper_config( - dotfile_path(), - subcommand_args.pep_config, - subcommand_args.output_dir, - subcommand_args.sample_pipeline_interfaces, - subcommand_args.project_pipeline_interfaces, - subcommand_args.force_yes, + + console = Console() + console.clear() + console.rule(f"\n[dark_goldenrod]Looper initialization[/dark_goldenrod]") + console.print("[bold]Would you like to follow a guided tutorial?[/bold] [green]Y[/green] / [red]n[/red]...") + + selection = None + while selection not in ['y','Y','n','N']: + selection = console.input("\nSelection: ") + + if selection in ['n', 'N']: + + return int( + not initiate_looper_config( + dotfile_path(), + subcommand_args.pep_config, + subcommand_args.output_dir, + subcommand_args.sample_pipeline_interfaces, + subcommand_args.project_pipeline_interfaces, + subcommand_args.force_yes, + ) ) - ) + else: + return int(looper_config_tutorial()) if subcommand_name == "init_piface": sys.exit(int(not init_generic_pipeline())) diff --git a/looper/utils.py b/looper/utils.py index 9c66d33da..4cd651d1d 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -21,6 +21,7 @@ from .const import * from .command_models.commands import SUPPORTED_COMMANDS from .exceptions import MisconfigurationException, PipelineInterfaceConfigError +from rich.console import Console _LOGGER = getLogger(__name__) @@ -535,6 +536,100 @@ def initiate_looper_config( print(f"Initialized looper config file: {looper_config_path}") return True +def looper_config_tutorial(): + # Prompt a user through configuring a .looper.yaml file for a new project. + # To be used in as an option for `looper init`. + + console = Console() + console.clear() + console.rule(f"\n[dark_goldenrod]Looper initialization[/dark_goldenrod]") + + looper_cfg_path = ".looper.yaml" # not changeable + + if os.path.exists(looper_cfg_path): + console.print(f"[bold red]File exists at '{looper_cfg_path}'. Delete it to re-initialize. \n[/bold red]") + raise SystemExit + + cfg = {} + + console.print("This utility will walk you through creating a [yellow].looper.yaml[/yellow] file.") + console.print("See [yellow]`looper init --help`[/yellow] for details.") + console.print("Use [yellow]`looper run`[/yellow] afterwards to run the pipeline.") + console.print("Press [yellow]^C[/yellow] at any time to quit.\n") + + console.input("> ... ") + + DEFAULTS = { # What you get if you just press enter + "pep_config": "databio/example", + "output_dir": "results", + "piface_path": "pipeline_interface.yaml", + "project_name": os.path.basename(os.getcwd()), + } + + creating = True + + while creating: + cfg["project_name"] = ( + console.input(f"Project name: [yellow]({DEFAULTS['project_name']})[/yellow] >") or DEFAULTS["project_name"] + ) + + cfg["pep_config"] = ( + console.input(f"Registry path or file path to PEP: [yellow]({DEFAULTS['pep_config']})[/yellow] >") + or DEFAULTS["pep_config"] + ) + + if not os.path.exists(cfg["pep_config"]): + console.print(f"Warning: PEP file does not exist at [yellow]'{cfg['pep_config']}[/yellow]'") + + cfg["output_dir"] = ( + console.input(f"Path to output directory: [yellow]({DEFAULTS['output_dir']})[/yellow] >") + or DEFAULTS["output_dir"] + ) + + # TODO: Right now this assumes you will have one pipeline interface, and a sample pipeline + # but this is not the only way you could configure things. + + piface_path = ( + console.input("Path to sample pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >") + or DEFAULTS["piface_path"] + ) + console.print("\n") + + console.print( f"""\ + [yellow]pep_config:[/yellow] {cfg['pep_config']} + [yellow]output_dir:[/yellow] {cfg['output_dir']} + [yellow]pipeline_interfaces:[/yellow] + - {piface_path} + """) + + console.print("[bold]Does this look good?[/bold] [bold green]Y[/bold green]/[red]n[/red]...") + selection = None + while selection not in ['y','Y','n','N']: + selection = console.input("\nSelection: ") + if selection in ['n', 'N']: + console.print("Starting over...") + pass + if selection in ['y', 'Y']: + creating=False + + if not os.path.exists(piface_path): + console.print(f"[bold red]Warning:[/bold red] file does not exist at [yellow]{piface_path}[/yellow]") + + console.print(f"Writing config file to [yellow]{looper_cfg_path}[/yellow]") + # print(f"PEP path: {cfg['pep_config']}") + # print(f"Pipeline interface path: {piface_path}") + + with open(looper_cfg_path, "w") as fp: + fp.write( + f"""\ + pep_config: {cfg['pep_config']} + output_dir: {cfg['output_dir']} + pipeline_interfaces: + - {piface_path} + """ + ) + + return True def determine_pipeline_type(piface_path: str, looper_config_path: str): """ diff --git a/looper_init.py b/looper_init.py deleted file mode 100644 index 9d7a3c5f3..000000000 --- a/looper_init.py +++ /dev/null @@ -1,68 +0,0 @@ -# A simple utility, to be run in the root of a project, to prompt a user through -# configuring a .looper.yaml file for a new project. To be used as `looper init`. - -import os - -cfg = {} - -print("This utility will walk you through creating a .looper.yaml file.") -print("See `looper init --help` for details.") -print("Use `looper run` afterwards to run the pipeline.") -print("Press ^C at any time to quit.\n") - -looper_cfg_path = ".looper.yaml" # not changeable - -if os.path.exists(looper_cfg_path): - print(f"File exists at '{looper_cfg_path}'. Delete it to re-initialize.") - raise SystemExit - -DEFAULTS = { # What you get if you just press enter - "pep_config": "databio/example", - "output_dir": "results", - "piface_path": "pipeline_interface.yaml", - "project_name": os.path.basename(os.getcwd()), -} - - -cfg["project_name"] = ( - input(f"Project name: ({DEFAULTS['project_name']}) ") or DEFAULTS["project_name"] -) - -cfg["pep_config"] = ( - input(f"Registry path or file path to PEP: ({DEFAULTS['pep_config']}) ") - or DEFAULTS["pep_config"] -) - -if not os.path.exists(cfg["pep_config"]): - print(f"Warning: PEP file does not exist at '{cfg['pep_config']}'") - -cfg["output_dir"] = ( - input(f"Path to output directory: ({DEFAULTS['output_dir']}) ") - or DEFAULTS["output_dir"] -) - -# TODO: Right now this assumes you will have one pipeline interface, and a sample pipeline -# but this is not the only way you could configure things. - -piface_path = ( - input("Path to sample pipeline interface: (pipeline_interface.yaml) ") - or DEFAULTS["piface_path"] -) - -if not os.path.exists(piface_path): - print(f"Warning: file does not exist at {piface_path}") - -print(f"Writing config file to {looper_cfg_path}") -print(f"PEP path: {cfg['pep_config']}") -print(f"Pipeline interface path: {piface_path}") - - -with open(looper_cfg_path, "w") as fp: - fp.write( - f"""\ -pep_config: {cfg['pep_config']} -output_dir: {cfg['output_dir']} -pipeline_interfaces: - sample: {piface_path} -""" - ) diff --git a/tests/smoketests/test_run.py b/tests/smoketests/test_run.py index d120722e4..948740ac1 100644 --- a/tests/smoketests/test_run.py +++ b/tests/smoketests/test_run.py @@ -588,7 +588,7 @@ def test_cli_compute_overwrites_yaml_settings_spec(self, prep_temp_pep, cmd): subs_list = [os.path.join(sd, f) for f in os.listdir(sd) if f.endswith(".sub")] assert_content_not_in_any_files(subs_list, "testin_mem") - +@pytest.mark.skip(reason="This functionality requires input from the user. Causing pytest to error if run without -s flag") class TestLooperConfig: def test_init_config_file(self, prep_temp_pep): From db29fd9a67cb11769b906af74ff1cd40488624df Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:36:09 -0400 Subject: [PATCH 2/8] lint --- looper/cli_pydantic.py | 11 ++++--- looper/utils.py | 59 +++++++++++++++++++++++++----------- tests/smoketests/test_run.py | 5 ++- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index a9b762c3d..7037616d9 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -53,7 +53,8 @@ init_generic_pipeline, read_yaml_file, inspect_looper_config_file, - is_PEP_file_type, looper_config_tutorial, + is_PEP_file_type, + looper_config_tutorial, ) from typing import List, Tuple @@ -127,13 +128,15 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): console = Console() console.clear() console.rule(f"\n[dark_goldenrod]Looper initialization[/dark_goldenrod]") - console.print("[bold]Would you like to follow a guided tutorial?[/bold] [green]Y[/green] / [red]n[/red]...") + console.print( + "[bold]Would you like to follow a guided tutorial?[/bold] [green]Y[/green] / [red]n[/red]..." + ) selection = None - while selection not in ['y','Y','n','N']: + while selection not in ["y", "Y", "n", "N"]: selection = console.input("\nSelection: ") - if selection in ['n', 'N']: + if selection in ["n", "N"]: return int( not initiate_looper_config( diff --git a/looper/utils.py b/looper/utils.py index 4cd651d1d..b9804b298 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -536,6 +536,7 @@ def initiate_looper_config( print(f"Initialized looper config file: {looper_config_path}") return True + def looper_config_tutorial(): # Prompt a user through configuring a .looper.yaml file for a new project. # To be used in as an option for `looper init`. @@ -547,12 +548,16 @@ def looper_config_tutorial(): looper_cfg_path = ".looper.yaml" # not changeable if os.path.exists(looper_cfg_path): - console.print(f"[bold red]File exists at '{looper_cfg_path}'. Delete it to re-initialize. \n[/bold red]") + console.print( + f"[bold red]File exists at '{looper_cfg_path}'. Delete it to re-initialize. \n[/bold red]" + ) raise SystemExit cfg = {} - console.print("This utility will walk you through creating a [yellow].looper.yaml[/yellow] file.") + console.print( + "This utility will walk you through creating a [yellow].looper.yaml[/yellow] file." + ) console.print("See [yellow]`looper init --help`[/yellow] for details.") console.print("Use [yellow]`looper run`[/yellow] afterwards to run the pipeline.") console.print("Press [yellow]^C[/yellow] at any time to quit.\n") @@ -570,50 +575,67 @@ def looper_config_tutorial(): while creating: cfg["project_name"] = ( - console.input(f"Project name: [yellow]({DEFAULTS['project_name']})[/yellow] >") or DEFAULTS["project_name"] + console.input( + f"Project name: [yellow]({DEFAULTS['project_name']})[/yellow] >" + ) + or DEFAULTS["project_name"] ) cfg["pep_config"] = ( - console.input(f"Registry path or file path to PEP: [yellow]({DEFAULTS['pep_config']})[/yellow] >") - or DEFAULTS["pep_config"] + console.input( + f"Registry path or file path to PEP: [yellow]({DEFAULTS['pep_config']})[/yellow] >" + ) + or DEFAULTS["pep_config"] ) if not os.path.exists(cfg["pep_config"]): - console.print(f"Warning: PEP file does not exist at [yellow]'{cfg['pep_config']}[/yellow]'") + console.print( + f"Warning: PEP file does not exist at [yellow]'{cfg['pep_config']}[/yellow]'" + ) cfg["output_dir"] = ( - console.input(f"Path to output directory: [yellow]({DEFAULTS['output_dir']})[/yellow] >") - or DEFAULTS["output_dir"] + console.input( + f"Path to output directory: [yellow]({DEFAULTS['output_dir']})[/yellow] >" + ) + or DEFAULTS["output_dir"] ) # TODO: Right now this assumes you will have one pipeline interface, and a sample pipeline # but this is not the only way you could configure things. piface_path = ( - console.input("Path to sample pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >") - or DEFAULTS["piface_path"] + console.input( + "Path to sample pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >" + ) + or DEFAULTS["piface_path"] ) console.print("\n") - console.print( f"""\ + console.print( + f"""\ [yellow]pep_config:[/yellow] {cfg['pep_config']} [yellow]output_dir:[/yellow] {cfg['output_dir']} [yellow]pipeline_interfaces:[/yellow] - {piface_path} - """) + """ + ) - console.print("[bold]Does this look good?[/bold] [bold green]Y[/bold green]/[red]n[/red]...") + console.print( + "[bold]Does this look good?[/bold] [bold green]Y[/bold green]/[red]n[/red]..." + ) selection = None - while selection not in ['y','Y','n','N']: + while selection not in ["y", "Y", "n", "N"]: selection = console.input("\nSelection: ") - if selection in ['n', 'N']: + if selection in ["n", "N"]: console.print("Starting over...") pass - if selection in ['y', 'Y']: - creating=False + if selection in ["y", "Y"]: + creating = False if not os.path.exists(piface_path): - console.print(f"[bold red]Warning:[/bold red] file does not exist at [yellow]{piface_path}[/yellow]") + console.print( + f"[bold red]Warning:[/bold red] file does not exist at [yellow]{piface_path}[/yellow]" + ) console.print(f"Writing config file to [yellow]{looper_cfg_path}[/yellow]") # print(f"PEP path: {cfg['pep_config']}") @@ -631,6 +653,7 @@ def looper_config_tutorial(): return True + def determine_pipeline_type(piface_path: str, looper_config_path: str): """ Read pipeline interface from disk and determine if it contains "sample_interface", "project_interface" or both diff --git a/tests/smoketests/test_run.py b/tests/smoketests/test_run.py index 948740ac1..e1da06fd9 100644 --- a/tests/smoketests/test_run.py +++ b/tests/smoketests/test_run.py @@ -588,7 +588,10 @@ def test_cli_compute_overwrites_yaml_settings_spec(self, prep_temp_pep, cmd): subs_list = [os.path.join(sd, f) for f in os.listdir(sd) if f.endswith(".sub")] assert_content_not_in_any_files(subs_list, "testin_mem") -@pytest.mark.skip(reason="This functionality requires input from the user. Causing pytest to error if run without -s flag") + +@pytest.mark.skip( + reason="This functionality requires input from the user. Causing pytest to error if run without -s flag" +) class TestLooperConfig: def test_init_config_file(self, prep_temp_pep): From acc02abd5a2a3f9618efcac35ab4c3a542883ef2 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:16:45 -0400 Subject: [PATCH 3/8] add changes to init_piface, change colors for better contrast --- looper/cli_pydantic.py | 5 +-- looper/utils.py | 78 +++++++++++++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index 7037616d9..cb619b37f 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -127,7 +127,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): console = Console() console.clear() - console.rule(f"\n[dark_goldenrod]Looper initialization[/dark_goldenrod]") + console.rule(f"\n[magenta]Looper initialization[/magenta]") console.print( "[bold]Would you like to follow a guided tutorial?[/bold] [green]Y[/green] / [red]n[/red]..." ) @@ -137,7 +137,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): selection = console.input("\nSelection: ") if selection in ["n", "N"]: - + console.clear() return int( not initiate_looper_config( dotfile_path(), @@ -149,6 +149,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): ) ) else: + console.clear() return int(looper_config_tutorial()) if subcommand_name == "init_piface": diff --git a/looper/utils.py b/looper/utils.py index b9804b298..671927115 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -22,6 +22,7 @@ from .command_models.commands import SUPPORTED_COMMANDS from .exceptions import MisconfigurationException, PipelineInterfaceConfigError from rich.console import Console +from rich.pretty import pprint _LOGGER = getLogger(__name__) @@ -407,6 +408,8 @@ def init_generic_pipeline(): """ Create generic pipeline interface """ + console = Console() + try: os.makedirs("pipeline") except FileExistsError: @@ -418,21 +421,26 @@ def init_generic_pipeline(): # Create Generic Pipeline Interface generic_pipeline_dict = { "pipeline_name": "default_pipeline_name", - "pipeline_type": "sample", "output_schema": "output_schema.yaml", - "var_templates": {"pipeline": "{looper.piface_dir}/pipeline.sh"}, - "command_template": "{pipeline.var_templates.pipeline} {sample.file} " - "--output-parent {looper.sample_output_folder}", + "var_templates": {"pipeline": "{looper.piface_dir}/count_lines.sh"}, + "sample_interface": { + "command_template": "{pipeline.var_templates.pipeline} {sample.file} " + "--output-parent {looper.sample_output_folder}" + }, } + console.rule(f"\n[magenta]Pipeline Interface[/magenta]") # Write file if not os.path.exists(dest_file): + pprint(generic_pipeline_dict, expand_all=True) with open(dest_file, "w") as file: yaml.dump(generic_pipeline_dict, file) - print(f"Pipeline interface successfully created at: {dest_file}") + console.print( + f"Pipeline interface successfully created at: [yellow]{dest_file}[/yellow]" + ) else: - print( - f"Pipeline interface file already exists `{dest_file}`. Skipping creation.." + console.print( + f"Pipeline interface file already exists [yellow]`{dest_file}`[/yellow]. Skipping creation.." ) # Create Generic Output Schema @@ -446,14 +454,22 @@ def init_generic_pipeline(): } }, } + + console.rule(f"\n[magenta]Output Schema[/magenta]") # Write file if not os.path.exists(dest_file): + pprint(generic_output_schema_dict, expand_all=True) with open(dest_file, "w") as file: yaml.dump(generic_output_schema_dict, file) - print(f"Output schema successfully created at: {dest_file}") + console.print( + f"Output schema successfully created at: [yellow]{dest_file}[/yellow]" + ) else: - print(f"Output schema file already exists `{dest_file}`. Skipping creation..") + console.print( + f"Output schema file already exists [yellow]`{dest_file}`[/yellow]. Skipping creation.." + ) + console.rule(f"\n[magenta]Example Pipeline Shell Script[/magenta]") # Create Generic countlines.sh dest_file = os.path.join(os.getcwd(), "pipeline", LOOPER_GENERIC_COUNT_LINES) shell_code = """#!/bin/bash @@ -462,11 +478,16 @@ def init_generic_pipeline(): echo "Number of lines: $linecount" """ if not os.path.exists(dest_file): + console.print(shell_code) with open(dest_file, "w") as file: file.write(shell_code) - print(f"count_lines.sh successfully created at: {dest_file}") + console.print( + f"count_lines.sh successfully created at: [yellow]{dest_file}[/yellow]" + ) else: - print(f"count_lines.sh file already exists `{dest_file}`. Skipping creation..") + console.print( + f"count_lines.sh file already exists [yellow]`{dest_file}`[/yellow]. Skipping creation.." + ) return True @@ -501,8 +522,14 @@ def initiate_looper_config( :param bool force: whether the existing file should be overwritten :return bool: whether the file was initialized """ + console = Console() + console.clear() + console.rule(f"\n[magenta]Looper initialization[/magenta]") + if os.path.exists(looper_config_path) and not force: - print(f"Can't initialize, file exists: {looper_config_path}") + console.print( + f"[red]Can't initialize, file exists:[/red] [yellow]{looper_config_path}[/yellow]" + ) return False if pep_path: @@ -522,18 +549,29 @@ def initiate_looper_config( if not output_dir: output_dir = "." + if sample_pipeline_interfaces is None or sample_pipeline_interfaces == []: + sample_pipeline_interfaces = "pipeline_interface1.yaml" + + if project_pipeline_interfaces is None or project_pipeline_interfaces == []: + project_pipeline_interfaces = "pipeline_interface2.yaml" + looper_config_dict = { "pep_config": os.path.relpath(pep_path), "output_dir": output_dir, - "pipeline_interfaces": { - "sample": sample_pipeline_interfaces, - "project": project_pipeline_interfaces, - }, + "pipeline_interfaces": [ + sample_pipeline_interfaces, + project_pipeline_interfaces, + ], } + pprint(looper_config_dict, expand_all=True) + with open(looper_config_path, "w") as dotfile: yaml.dump(looper_config_dict, dotfile) - print(f"Initialized looper config file: {looper_config_path}") + console.print( + f"Initialized looper config file: [yellow]{looper_config_path}[/yellow]" + ) + return True @@ -543,7 +581,7 @@ def looper_config_tutorial(): console = Console() console.clear() - console.rule(f"\n[dark_goldenrod]Looper initialization[/dark_goldenrod]") + console.rule(f"\n[magenta]Looper initialization[/magenta]") looper_cfg_path = ".looper.yaml" # not changeable @@ -567,7 +605,7 @@ def looper_config_tutorial(): DEFAULTS = { # What you get if you just press enter "pep_config": "databio/example", "output_dir": "results", - "piface_path": "pipeline_interface.yaml", + "piface_path": "pipeline/pipeline_interface.yaml", "project_name": os.path.basename(os.getcwd()), } @@ -634,7 +672,7 @@ def looper_config_tutorial(): if not os.path.exists(piface_path): console.print( - f"[bold red]Warning:[/bold red] file does not exist at [yellow]{piface_path}[/yellow]" + f"[bold red]Warning:[/bold red] File does not exist at [yellow]{piface_path}[/yellow]\nUse command [yellow]`looper init_piface`[/yellow] to create a generic pipeline interface." ) console.print(f"Writing config file to [yellow]{looper_cfg_path}[/yellow]") From 0ffb6349a1f911e97e1ff44816ee839f78a34856 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:48:22 -0400 Subject: [PATCH 4/8] Update looper/cli_pydantic.py Co-authored-by: Oleksandr --- looper/cli_pydantic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index cb619b37f..7ce1dacba 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -133,8 +133,8 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): ) selection = None - while selection not in ["y", "Y", "n", "N"]: - selection = console.input("\nSelection: ") + while selection not in ["y", "n"]: + selection = console.input("\nSelection: ").lower().strip() if selection in ["n", "N"]: console.clear() From f63597cb4e22b31bd6f68b05fcf038e91ae8d2eb Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:48:32 -0400 Subject: [PATCH 5/8] Update looper/cli_pydantic.py Co-authored-by: Oleksandr --- looper/cli_pydantic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index 7ce1dacba..42078b840 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -136,7 +136,7 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): while selection not in ["y", "n"]: selection = console.input("\nSelection: ").lower().strip() - if selection in ["n", "N"]: + if selection == "n": console.clear() return int( not initiate_looper_config( From a24e0e8d4f1e9295ac6c97a8cfd2d8450bb0bb86 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:52:16 -0400 Subject: [PATCH 6/8] simplify selection options --- looper/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/looper/utils.py b/looper/utils.py index 671927115..79bbd51e3 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -662,12 +662,12 @@ def looper_config_tutorial(): "[bold]Does this look good?[/bold] [bold green]Y[/bold green]/[red]n[/red]..." ) selection = None - while selection not in ["y", "Y", "n", "N"]: - selection = console.input("\nSelection: ") - if selection in ["n", "N"]: + while selection not in ["y", "n"]: + selection = console.input("\nSelection: ").lower().strip() + if selection == "n": console.print("Starting over...") pass - if selection in ["y", "Y"]: + if selection == "y": creating = False if not os.path.exists(piface_path): From 9d4551e6ba8aba88a7cd2d1cf783b62d91356bc6 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:54:18 -0400 Subject: [PATCH 7/8] add docstrings --- looper/utils.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/looper/utils.py b/looper/utils.py index 79bbd51e3..2da99559f 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -576,8 +576,11 @@ def initiate_looper_config( def looper_config_tutorial(): - # Prompt a user through configuring a .looper.yaml file for a new project. - # To be used in as an option for `looper init`. + """ + Prompt a user through configuring a .looper.yaml file for a new project. + + :return bool: whether the file was initialized + """ console = Console() console.clear() From cc1b1ad5eb0d90f7b1056625094004a882a059a0 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 1 Jul 2024 13:03:43 -0400 Subject: [PATCH 8/8] fix looper config formatting on write --- looper/utils.py | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/looper/utils.py b/looper/utils.py index 2da99559f..328d3402b 100644 --- a/looper/utils.py +++ b/looper/utils.py @@ -641,9 +641,6 @@ def looper_config_tutorial(): or DEFAULTS["output_dir"] ) - # TODO: Right now this assumes you will have one pipeline interface, and a sample pipeline - # but this is not the only way you could configure things. - piface_path = ( console.input( "Path to sample pipeline interface: [yellow](pipeline_interface.yaml)[/yellow] >" @@ -679,18 +676,14 @@ def looper_config_tutorial(): ) console.print(f"Writing config file to [yellow]{looper_cfg_path}[/yellow]") - # print(f"PEP path: {cfg['pep_config']}") - # print(f"Pipeline interface path: {piface_path}") + + looper_config_dict = {} + looper_config_dict["pep_config"] = cfg["pep_config"] + looper_config_dict["output_dir"] = cfg["output_dir"] + looper_config_dict["pipeline_interfaces"] = [piface_path] with open(looper_cfg_path, "w") as fp: - fp.write( - f"""\ - pep_config: {cfg['pep_config']} - output_dir: {cfg['output_dir']} - pipeline_interfaces: - - {piface_path} - """ - ) + yaml.dump(looper_config_dict, fp) return True