From 13499b5d3be5c9647de48a48ffd60b9a0520eac1 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 13 May 2024 11:28:03 -0400 Subject: [PATCH 1/9] test workaround for shortform arguments --- looper/cli_pydantic.py | 45 ++++++++++++++++++++++++++++++++++-- tests/smoketests/test_run.py | 10 ++++++++ tests/test_comprehensive.py | 1 + 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index f9c51009..58798711 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -53,6 +53,22 @@ from typing import List, Tuple +run_arguments_dict = { + "-d": "--dry-run", + "-l": "--limit", + "-k": "--skip", + "-o": "--output-dir", + "-S": "--sample-pipeline-interfaces", + "-P": "--project-pipeline-interfaces", + "-p": "--piface", + "-i": "--ignore-flags", + "-t": "--time-delay", + "-x": "--command-extra", + "-y": "--command-extra-override", + "-f": "--skip-file-checks", +} + + def opt_attr_pair(name: str) -> Tuple[str, str]: """Takes argument as attribute and returns as tuple of top-level or subcommand used.""" return f"--{name}", name.replace("-", "_") @@ -310,6 +326,27 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): _LOGGER.warning("No looper configuration was supplied.") +def create_command_string(args, command): + """ + This is a workaround for short form arguments not being supported by the pydantic argparse package + """ + arguments_dict = {} + + # Must determine argument dict based on command since there is overlap in shortform keys... + if command in ["run", "runp", "rerun"]: + arguments_dict = run_arguments_dict + + modified_command_string = [] + for arg in args: + replacement = arguments_dict.get(arg) + modified_command_string.append(replacement if replacement else arg) + + if command not in modified_command_string: + modified_command_string.insert(command) + + return modified_command_string + + def main(test_args=None) -> None: parser = pydantic2_argparse.ArgumentParser( model=TopLevelParser, @@ -318,9 +355,13 @@ def main(test_args=None) -> None: add_help=True, ) if test_args: - args = parser.parse_typed_args(args=test_args) + command_string = create_command_string(args=test_args, command=test_args[0]) else: - args = parser.parse_typed_args() + sys_args = sys.argv[1:] + command_string = create_command_string(args=sys_args, command=sys_args[0]) + + args = parser.parse_typed_args(args=command_string) + return run_looper(args, parser, test_args=test_args) diff --git a/tests/smoketests/test_run.py b/tests/smoketests/test_run.py index 828e210a..dda6499d 100644 --- a/tests/smoketests/test_run.py +++ b/tests/smoketests/test_run.py @@ -23,6 +23,16 @@ def test_cli(prep_temp_pep): raise pytest.fail("DID RAISE {0}".format(Exception)) +def test_cli_shortform(prep_temp_pep): + tp = prep_temp_pep + + x = ["run", "--looper-config", tp, "-d"] + try: + main(test_args=x) + except Exception: + raise pytest.fail("DID RAISE {0}".format(Exception)) + + def test_running_csv_pep(prep_temp_pep_csv): tp = prep_temp_pep_csv diff --git a/tests/test_comprehensive.py b/tests/test_comprehensive.py index f03f0692..52385783 100644 --- a/tests/test_comprehensive.py +++ b/tests/test_comprehensive.py @@ -149,6 +149,7 @@ def test_comprehensive_looper_pipestat(prep_temp_pep_pipestat): @pytest.mark.skipif(not is_connected(), reason="This test needs internet access.") +@pytest.mark.skip("Test broken") def test_comprehensive_looper_pephub(prep_temp_pep_pephub): """Basic test to determine if Looper can run a PEP from PEPHub""" From d1b93f1b7e11bfcbc105d3901f08a56049849f2c Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 13 May 2024 12:04:02 -0400 Subject: [PATCH 2/9] add more arguments dictionaries, doc strings, --- looper/cli_pydantic.py | 69 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index 58798711..e5fad451 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -55,6 +55,7 @@ run_arguments_dict = { "-d": "--dry-run", + "-c": "--compute", "-l": "--limit", "-k": "--skip", "-o": "--output-dir", @@ -66,6 +67,47 @@ "-x": "--command-extra", "-y": "--command-extra-override", "-f": "--skip-file-checks", + "-u": "--lump-s", + "-n": "--lump-n", + "-j": "--lump-j", +} + +init_arguments_dict = { + "-d": "--dry-run", + "-c": "--compute", + "-l": "--limit", + "-k": "--skip", + "-o": "--output-dir", + "-S": "--sample-pipeline-interfaces", + "-P": "--project-pipeline-interfaces", + "-p": "--piface", + "-i": "--ignore-flags", + "-t": "--time-delay", + "-x": "--command-extra", + "-y": "--command-extra-override", + "-f": "--force", + "-u": "--lump-s", + "-n": "--lump-n", + "-j": "--lump-j", +} + +check_arguments_dict = { + "-d": "--dry-run", + "-c": "--compute", + "-l": "--limit", + "-k": "--skip", + "-o": "--output-dir", + "-S": "--sample-pipeline-interfaces", + "-P": "--project-pipeline-interfaces", + "-p": "--piface", + "-i": "--ignore-flags", + "-t": "--time-delay", + "-x": "--command-extra", + "-y": "--command-extra-override", + "-f": "--flags", + "-u": "--lump-s", + "-n": "--lump-n", + "-j": "--lump-j", } @@ -326,22 +368,41 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): _LOGGER.warning("No looper configuration was supplied.") -def create_command_string(args, command): +def create_command_string(args: list[str], command: str): """ - This is a workaround for short form arguments not being supported by the pydantic argparse package + This is a workaround for short form arguments not being supported by the pydantic argparse package. + :param args: list[str] taken from test_args or sys.argv + :param command: str high level command + :return modified_command_string: list[str] that has been modified, replacing shortforms with longforms """ arguments_dict = {} - # Must determine argument dict based on command since there is overlap in shortform keys... - if command in ["run", "runp", "rerun"]: + # Must determine argument dict based on command since there is overlap in shortform keys for a couple of commands + if command in [ + "run", + "runp", + "rerun", + "table", + "report", + "destroy", + "clean", + "inspect", + "link", + ]: arguments_dict = run_arguments_dict + if command in ["init"]: + arguments_dict = init_arguments_dict + if command in ["check"]: + arguments_dict = check_arguments_dict modified_command_string = [] for arg in args: + # Replace shortform with long form based on the dictionary replacement = arguments_dict.get(arg) modified_command_string.append(replacement if replacement else arg) if command not in modified_command_string: + # required when using sys.argv during normal usage i.e. not test_args modified_command_string.insert(command) return modified_command_string From c35dcb0b604cffc74dab5c12ba1a3f23b2021351 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Mon, 13 May 2024 13:05:13 -0400 Subject: [PATCH 3/9] revert skipping 1 test for pephub --- tests/test_comprehensive.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_comprehensive.py b/tests/test_comprehensive.py index 52385783..f03f0692 100644 --- a/tests/test_comprehensive.py +++ b/tests/test_comprehensive.py @@ -149,7 +149,6 @@ def test_comprehensive_looper_pipestat(prep_temp_pep_pipestat): @pytest.mark.skipif(not is_connected(), reason="This test needs internet access.") -@pytest.mark.skip("Test broken") def test_comprehensive_looper_pephub(prep_temp_pep_pephub): """Basic test to determine if Looper can run a PEP from PEPHub""" From 1cf1f9b790f3919085f90502bb8dd5ee46f33cf3 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 10:55:08 -0400 Subject: [PATCH 4/9] new approach to add short arguments by adding them to the parser object immediately after parser creation --- looper/cli_pydantic.py | 114 +++--------------------------- looper/command_models/commands.py | 42 +++++++++++ tests/smoketests/test_run.py | 13 ++++ 3 files changed, 65 insertions(+), 104 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index e5fad451..e9b0f7da 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -30,7 +30,11 @@ from divvy import select_divvy_config from . import __version__ -from .command_models.commands import SUPPORTED_COMMANDS, TopLevelParser +from .command_models.commands import ( + SUPPORTED_COMMANDS, + TopLevelParser, + add_short_arguments, +) from .const import * from .divvy import DEFAULT_COMPUTE_RESOURCES_NAME, select_divvy_config from .exceptions import * @@ -53,64 +57,6 @@ from typing import List, Tuple -run_arguments_dict = { - "-d": "--dry-run", - "-c": "--compute", - "-l": "--limit", - "-k": "--skip", - "-o": "--output-dir", - "-S": "--sample-pipeline-interfaces", - "-P": "--project-pipeline-interfaces", - "-p": "--piface", - "-i": "--ignore-flags", - "-t": "--time-delay", - "-x": "--command-extra", - "-y": "--command-extra-override", - "-f": "--skip-file-checks", - "-u": "--lump-s", - "-n": "--lump-n", - "-j": "--lump-j", -} - -init_arguments_dict = { - "-d": "--dry-run", - "-c": "--compute", - "-l": "--limit", - "-k": "--skip", - "-o": "--output-dir", - "-S": "--sample-pipeline-interfaces", - "-P": "--project-pipeline-interfaces", - "-p": "--piface", - "-i": "--ignore-flags", - "-t": "--time-delay", - "-x": "--command-extra", - "-y": "--command-extra-override", - "-f": "--force", - "-u": "--lump-s", - "-n": "--lump-n", - "-j": "--lump-j", -} - -check_arguments_dict = { - "-d": "--dry-run", - "-c": "--compute", - "-l": "--limit", - "-k": "--skip", - "-o": "--output-dir", - "-S": "--sample-pipeline-interfaces", - "-P": "--project-pipeline-interfaces", - "-p": "--piface", - "-i": "--ignore-flags", - "-t": "--time-delay", - "-x": "--command-extra", - "-y": "--command-extra-override", - "-f": "--flags", - "-u": "--lump-s", - "-n": "--lump-n", - "-j": "--lump-j", -} - - def opt_attr_pair(name: str) -> Tuple[str, str]: """Takes argument as attribute and returns as tuple of top-level or subcommand used.""" return f"--{name}", name.replace("-", "_") @@ -368,46 +314,6 @@ def run_looper(args: TopLevelParser, parser: ArgumentParser, test_args=None): _LOGGER.warning("No looper configuration was supplied.") -def create_command_string(args: list[str], command: str): - """ - This is a workaround for short form arguments not being supported by the pydantic argparse package. - :param args: list[str] taken from test_args or sys.argv - :param command: str high level command - :return modified_command_string: list[str] that has been modified, replacing shortforms with longforms - """ - arguments_dict = {} - - # Must determine argument dict based on command since there is overlap in shortform keys for a couple of commands - if command in [ - "run", - "runp", - "rerun", - "table", - "report", - "destroy", - "clean", - "inspect", - "link", - ]: - arguments_dict = run_arguments_dict - if command in ["init"]: - arguments_dict = init_arguments_dict - if command in ["check"]: - arguments_dict = check_arguments_dict - - modified_command_string = [] - for arg in args: - # Replace shortform with long form based on the dictionary - replacement = arguments_dict.get(arg) - modified_command_string.append(replacement if replacement else arg) - - if command not in modified_command_string: - # required when using sys.argv during normal usage i.e. not test_args - modified_command_string.insert(command) - - return modified_command_string - - def main(test_args=None) -> None: parser = pydantic2_argparse.ArgumentParser( model=TopLevelParser, @@ -415,13 +321,13 @@ def main(test_args=None) -> None: description="Looper Pydantic Argument Parser", add_help=True, ) + + parser = add_short_arguments(parser) + if test_args: - command_string = create_command_string(args=test_args, command=test_args[0]) + args = parser.parse_typed_args(args=test_args) else: - sys_args = sys.argv[1:] - command_string = create_command_string(args=sys_args, command=sys_args[0]) - - args = parser.parse_typed_args(args=command_string) + args = parser.parse_typed_args() return run_looper(args, parser, test_args=test_args) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index 653df6e2..3dc4c0d4 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -234,6 +234,48 @@ def create_model(self) -> Type[pydantic.BaseModel]: InitPifaceParserModel = InitPifaceParser.create_model() +def add_short_arguments(parser): + """ + This function takes a parser object created under pydantic argparse and adds the short arguments AFTER the initial creation. + This is a workaround as pydantic-argparse does not currently support this during initial parser creation. + """ + # Loop through commands, add relevant short arguments + + short_arguments_dict = { + "--dry-run": "-d", + "--limit": "-l", + "--compute": "-c", + "--skip": "-k", + "--output-dir": "-o", + "--sample-pipeline-interfaces": "-S", + "--project-pipeline-interfaces": "-P", + "--piface": "-p", + "--ignore-flags": "-i", + "--time-delay": "-t", + "--command-extra": "-x", + "--command-extra-override": "-y", + "--lump-s": "-u", + "--lump-n": "-n", + "--lump-j": "-j", + "--skip-file-checks": "-f", + "--force": "-f", + "--flags": "-f", + } + + for cmd in parser._subcommands.choices.keys(): + for long_key, short_key in short_arguments_dict.items(): + if long_key in parser._subcommands.choices[cmd]._option_string_actions: + argument = parser._subcommands.choices[cmd]._option_string_actions[ + long_key + ] + argument.option_strings = (short_key, long_key) + parser._subcommands.choices[cmd]._option_string_actions[ + short_key + ] = argument + + return parser + + SUPPORTED_COMMANDS = [ RunParser, RerunParser, diff --git a/tests/smoketests/test_run.py b/tests/smoketests/test_run.py index dda6499d..05231f59 100644 --- a/tests/smoketests/test_run.py +++ b/tests/smoketests/test_run.py @@ -32,6 +32,19 @@ def test_cli_shortform(prep_temp_pep): except Exception: raise pytest.fail("DID RAISE {0}".format(Exception)) + x = ["run", "--looper-config", tp, "-d", "-l", "2"] + try: + main(test_args=x) + except Exception: + raise pytest.fail("DID RAISE {0}".format(Exception)) + + tp = prep_temp_pep + x = ["run", "--looper-config", tp, "-d", "-n", "2"] + try: + main(test_args=x) + except Exception: + raise pytest.fail("DID RAISE {0}".format(Exception)) + def test_running_csv_pep(prep_temp_pep_csv): tp = prep_temp_pep_csv From 833c41c0097e4197db1cf6ad77a0799c63ead4db Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 11:27:45 -0400 Subject: [PATCH 5/9] fix force argument, add clarification for overlapping short form arguments --- looper/command_models/commands.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index 3dc4c0d4..cce321d0 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -240,6 +240,7 @@ def add_short_arguments(parser): This is a workaround as pydantic-argparse does not currently support this during initial parser creation. """ # Loop through commands, add relevant short arguments + # Note there are three long form arguments that have 'f' as a short form. However, they are used on 3 separate commands. short_arguments_dict = { "--dry-run": "-d", @@ -258,7 +259,7 @@ def add_short_arguments(parser): "--lump-n": "-n", "--lump-j": "-j", "--skip-file-checks": "-f", - "--force": "-f", + "--force-yes": "-f", "--flags": "-f", } From eca5c646dc4466799923b2f1995d8abbbef0c530 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 11:37:11 -0400 Subject: [PATCH 6/9] add docstrings --- looper/command_models/commands.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index cce321d0..dd0dc81c 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -9,6 +9,7 @@ from ..const import MESSAGE_BY_SUBCOMMAND from .arguments import Argument, ArgumentEnum +from pydantic2_argparse import ArgumentParser @dataclass @@ -234,10 +235,13 @@ def create_model(self) -> Type[pydantic.BaseModel]: InitPifaceParserModel = InitPifaceParser.create_model() -def add_short_arguments(parser): +def add_short_arguments(parser: ArgumentParser) -> ArgumentParser: """ This function takes a parser object created under pydantic argparse and adds the short arguments AFTER the initial creation. This is a workaround as pydantic-argparse does not currently support this during initial parser creation. + + :param ArgumentParser + :return ArgumentParser """ # Loop through commands, add relevant short arguments # Note there are three long form arguments that have 'f' as a short form. However, they are used on 3 separate commands. From db8f06401183a087d4d550009168daeccf082e62 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 14:37:57 -0400 Subject: [PATCH 7/9] use alias on ArgumentEnum to do key value replacement for short args --- looper/command_models/arguments.py | 34 ++++++++++++++++--- looper/command_models/commands.py | 52 +++++++++++------------------- 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/looper/command_models/arguments.py b/looper/command_models/arguments.py index 6cab9eaf..75855511 100644 --- a/looper/command_models/arguments.py +++ b/looper/command_models/arguments.py @@ -33,9 +33,13 @@ class Argument(pydantic.fields.FieldInfo): `FieldInfo`. These are passed along as they are. """ - def __init__(self, name: str, default: Any, description: str, **kwargs) -> None: + def __init__( + self, name: str, default: Any, description: str, alias: str = None, **kwargs + ) -> None: self._name = name - super().__init__(default=default, description=description, **kwargs) + super().__init__( + default=default, description=description, alias=alias, **kwargs + ) self._validate() @property @@ -77,11 +81,13 @@ class ArgumentEnum(enum.Enum): IGNORE_FLAGS = Argument( name="ignore_flags", + alias="-i", default=(bool, False), description="Ignore run status flags", ) FORCE_YES = Argument( name="force_yes", + alias="-f", default=(bool, False), description="Provide upfront confirmation of destruction intent, to skip console query. Default=False", ) @@ -100,48 +106,61 @@ class ArgumentEnum(enum.Enum): FLAGS = Argument( name="flags", + alias="-f", default=(List, []), description="Only check samples based on these status flags.", ) TIME_DELAY = Argument( name="time_delay", + alias="-t", default=(int, 0), description="Time delay in seconds between job submissions (min: 0, max: 30)", ) DRY_RUN = Argument( - name="dry_run", default=(bool, False), description="Don't actually submit jobs" + name="dry_run", + alias="-d", + default=(bool, False), + description="Don't actually submit jobs", ) COMMAND_EXTRA = Argument( name="command_extra", + alias="-x", default=(str, ""), description="String to append to every command", ) COMMAND_EXTRA_OVERRIDE = Argument( name="command_extra_override", + alias="-y", default=(str, ""), description="Same as command-extra, but overrides values in PEP", ) LUMP = Argument( name="lump", + alias="-u", default=(float, None), description="Total input file size (GB) to batch into one job", ) LUMPN = Argument( name="lump_n", + alias="-n", default=(int, None), description="Number of commands to batch into one job", ) LUMPJ = Argument( name="lump_j", + alias="-j", default=(int, None), description="Lump samples into number of jobs.", ) LIMIT = Argument( - name="limit", default=(int, None), description="Limit to n samples" + name="limit", alias="-l", default=(int, None), description="Limit to n samples" ) SKIP = Argument( - name="skip", default=(int, None), description="Skip samples by numerical index" + name="skip", + alias="-k", + default=(int, None), + description="Skip samples by numerical index", ) CONFIG_FILE = Argument( name="config_file", @@ -165,16 +184,19 @@ class ArgumentEnum(enum.Enum): ) OUTPUT_DIR = Argument( name="output_dir", + alias="-o", default=(str, None), description="Output directory", ) SAMPLE_PIPELINE_INTERFACES = Argument( name="sample_pipeline_interfaces", + alias="-S", default=(List, []), description="Paths to looper sample config files", ) PROJECT_PIPELINE_INTERFACES = Argument( name="project_pipeline_interfaces", + alias="-P", default=(List, []), description="Paths to looper project config files", ) @@ -204,6 +226,7 @@ class ArgumentEnum(enum.Enum): ) SKIP_FILE_CHECKS = Argument( name="skip_file_checks", + alias="-f", default=(bool, False), description="Do not perform input file checks", ) @@ -214,6 +237,7 @@ class ArgumentEnum(enum.Enum): ) COMPUTE = Argument( name="compute", + alias="-c", default=(List, []), description="List of key-value pairs (k1=v1)", ) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index dd0dc81c..b4613265 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -240,43 +240,27 @@ def add_short_arguments(parser: ArgumentParser) -> ArgumentParser: This function takes a parser object created under pydantic argparse and adds the short arguments AFTER the initial creation. This is a workaround as pydantic-argparse does not currently support this during initial parser creation. - :param ArgumentParser - :return ArgumentParser + :param ArgumentParser: parser before adding short arguments + :return ArgumentParser: parser after short arguments have been added """ - # Loop through commands, add relevant short arguments - # Note there are three long form arguments that have 'f' as a short form. However, they are used on 3 separate commands. - - short_arguments_dict = { - "--dry-run": "-d", - "--limit": "-l", - "--compute": "-c", - "--skip": "-k", - "--output-dir": "-o", - "--sample-pipeline-interfaces": "-S", - "--project-pipeline-interfaces": "-P", - "--piface": "-p", - "--ignore-flags": "-i", - "--time-delay": "-t", - "--command-extra": "-x", - "--command-extra-override": "-y", - "--lump-s": "-u", - "--lump-n": "-n", - "--lump-j": "-j", - "--skip-file-checks": "-f", - "--force-yes": "-f", - "--flags": "-f", - } for cmd in parser._subcommands.choices.keys(): - for long_key, short_key in short_arguments_dict.items(): - if long_key in parser._subcommands.choices[cmd]._option_string_actions: - argument = parser._subcommands.choices[cmd]._option_string_actions[ - long_key - ] - argument.option_strings = (short_key, long_key) - parser._subcommands.choices[cmd]._option_string_actions[ - short_key - ] = argument + + for argument_enum in list(ArgumentEnum): + # First check there is an alias for the argument otherwise skip + if argument_enum.value.alias: + short_key = argument_enum.value.alias + long_key = "--" + argument_enum.value.name.replace( + "_", "-" + ) # We must do this because the ArgumentEnum names are transformed during parser creation + if long_key in parser._subcommands.choices[cmd]._option_string_actions: + argument = parser._subcommands.choices[cmd]._option_string_actions[ + long_key + ] + argument.option_strings = (short_key, long_key) + parser._subcommands.choices[cmd]._option_string_actions[ + short_key + ] = argument return parser From 6bcc2cdf275cb6d8fa8c39fc38a2635ed5361ead Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 15:29:20 -0400 Subject: [PATCH 8/9] pass ArgumentEnums to function to make it explicit and not use lexical scoping --- looper/cli_pydantic.py | 5 ++++- looper/command_models/commands.py | 9 +++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/looper/cli_pydantic.py b/looper/cli_pydantic.py index e9b0f7da..924a6c7e 100644 --- a/looper/cli_pydantic.py +++ b/looper/cli_pydantic.py @@ -30,6 +30,9 @@ from divvy import select_divvy_config from . import __version__ + +from .command_models.arguments import ArgumentEnum + from .command_models.commands import ( SUPPORTED_COMMANDS, TopLevelParser, @@ -322,7 +325,7 @@ def main(test_args=None) -> None: add_help=True, ) - parser = add_short_arguments(parser) + parser = add_short_arguments(parser, ArgumentEnum) if test_args: args = parser.parse_typed_args(args=test_args) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index b4613265..b040d931 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -235,18 +235,19 @@ def create_model(self) -> Type[pydantic.BaseModel]: InitPifaceParserModel = InitPifaceParser.create_model() -def add_short_arguments(parser: ArgumentParser) -> ArgumentParser: +def add_short_arguments(parser: ArgumentParser, argument_enums: Type[ArgumentEnum]) -> ArgumentParser: """ This function takes a parser object created under pydantic argparse and adds the short arguments AFTER the initial creation. This is a workaround as pydantic-argparse does not currently support this during initial parser creation. - :param ArgumentParser: parser before adding short arguments - :return ArgumentParser: parser after short arguments have been added + :param ArgumentParser parser: parser before adding short arguments + :param Type[ArgumentEnum] argument_enums: enumeration of arguments that contain names and aliases + :return ArgumentParser parser: parser after short arguments have been added """ for cmd in parser._subcommands.choices.keys(): - for argument_enum in list(ArgumentEnum): + for argument_enum in list(argument_enums): # First check there is an alias for the argument otherwise skip if argument_enum.value.alias: short_key = argument_enum.value.alias From 206e47bd0a16856b78a75bd89dc238b6f0f4a524 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Wed, 15 May 2024 15:30:31 -0400 Subject: [PATCH 9/9] lint --- looper/command_models/commands.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/looper/command_models/commands.py b/looper/command_models/commands.py index b040d931..e9025d90 100644 --- a/looper/command_models/commands.py +++ b/looper/command_models/commands.py @@ -235,7 +235,9 @@ def create_model(self) -> Type[pydantic.BaseModel]: InitPifaceParserModel = InitPifaceParser.create_model() -def add_short_arguments(parser: ArgumentParser, argument_enums: Type[ArgumentEnum]) -> ArgumentParser: +def add_short_arguments( + parser: ArgumentParser, argument_enums: Type[ArgumentEnum] +) -> ArgumentParser: """ This function takes a parser object created under pydantic argparse and adds the short arguments AFTER the initial creation. This is a workaround as pydantic-argparse does not currently support this during initial parser creation.