From 6f9ff3ccfcc47f582fe59bf2400173cca8e68575 Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Mon, 30 May 2022 22:16:42 +0200 Subject: [PATCH 1/8] Add multiple option for args --- poethepoet/task/args.py | 52 ++++++++++++++++--- poethepoet/task/base.py | 15 ++++-- .../fixtures/scripts_project/pkg/__init__.py | 5 ++ tests/fixtures/scripts_project/pyproject.toml | 23 ++++++++ 4 files changed, 82 insertions(+), 13 deletions(-) diff --git a/poethepoet/task/args.py b/poethepoet/task/args.py index 796041d5b..1fd86da3c 100644 --- a/poethepoet/task/args.py +++ b/poethepoet/task/args.py @@ -26,6 +26,7 @@ "positional": (bool, str), "required": bool, "type": str, + "multiple": (bool, int), } arg_types: Dict[str, Type] = { "string": str, @@ -96,6 +97,8 @@ def get_help_content( @classmethod def validate_def(cls, task_name: str, args_def: ArgsDef) -> Optional[str]: arg_names: Set[str] = set() + arg_params = [] + if isinstance(args_def, list): for item in args_def: # can be a list of strings (just arg name) or ArgConfig dictionaries @@ -103,14 +106,13 @@ def validate_def(cls, task_name: str, args_def: ArgsDef) -> Optional[str]: arg_name = item elif isinstance(item, dict): arg_name = item.get("name", "") - error = cls._validate_params(item, arg_name, task_name) - if error: - return error + arg_params.append((item, arg_name, task_name)) else: return f"Arg {item!r} of task {task_name!r} has invlaid type" error = cls._validate_name(arg_name, task_name, arg_names) if error: return error + elif isinstance(args_def, dict): for arg_name, params in args_def.items(): error = cls._validate_name(arg_name, task_name, arg_names) @@ -121,12 +123,26 @@ def validate_def(cls, task_name: str, args_def: ArgsDef) -> Optional[str]: f"Unexpected 'name' option for arg {arg_name!r} of task " f"{task_name!r}" ) - error = cls._validate_params(params, arg_name, task_name) - if error: - return error error = cls._validate_type(params, arg_name, task_name) if error: return error + arg_params.append((params, arg_name, task_name)) + + positional_multiple = None + for params, arg_name, task_name in arg_params: + error = cls._validate_params(params, arg_name, task_name) + if error: + return error + + if params.get("positional", False): + if positional_multiple: + return ( + f"Only the last positional arg of task {task_name!r} may accept" + f" multiple values ({positional_multiple!r})." + ) + if params.get("multiple", False): + positional_multiple = arg_name + return None @classmethod @@ -182,6 +198,17 @@ def _validate_params( "https://docs.python.org/3/reference/lexical_analysis.html#identifiers" ) + multiple = params.get("multiple", False) + if ( + not isinstance(multiple, bool) + and isinstance(multiple, int) + and multiple < 2 + ): + return ( + f"The multiple option for arg {arg_name!r} of {task_name!r}" + " must be given a boolean or integer >= 2" + ) + return None @classmethod @@ -217,10 +244,19 @@ def _get_argument_params(self, arg: ArgParams): } required = arg.get("required", False) + multiple = arg.get("multiple", False) arg_type = str(arg.get("type")) + if multiple is True: + if required: + result["nargs"] = "+" + else: + result["nargs"] = "*" + elif isinstance(multiple, int): + result["nargs"] = multiple + if arg.get("positional", False): - if not required: + if not multiple and not required: result["nargs"] = "?" else: result["dest"] = arg["name"] @@ -235,7 +271,7 @@ def _get_argument_params(self, arg: ArgParams): def parse(self, extra_args: Sequence[str]): parsed_args = vars(self.build_parser().parse_args(extra_args)) - # Ensure positional args are still exposed by name even if the were parsed with + # Ensure positional args are still exposed by name even if they were parsed with # alternate identifiers for arg in self._args: if isinstance(arg.get("positional"), str): diff --git a/poethepoet/task/base.py b/poethepoet/task/base.py index 322db5d95..d30df3b22 100644 --- a/poethepoet/task/base.py +++ b/poethepoet/task/base.py @@ -196,13 +196,18 @@ def has_named_args(self): return bool(self.named_args) def get_named_arg_values(self) -> Mapping[str, str]: + result = {} + if not self.named_args: return {} - return { - key: str(value) - for key, value in self.named_args.items() - if value is not None - } + + for key, value in self.named_args.items(): + if isinstance(value, list): + result[key] = " ".join(str(item) for item in value) + elif value is not None: + result[key] = str(value) + + return result def run( self, diff --git a/tests/fixtures/scripts_project/pkg/__init__.py b/tests/fixtures/scripts_project/pkg/__init__.py index b266ac18e..76152bc86 100644 --- a/tests/fixtures/scripts_project/pkg/__init__.py +++ b/tests/fixtures/scripts_project/pkg/__init__.py @@ -15,6 +15,11 @@ def echo_args(): print("hello", *sys.argv[1:]) +def echo_script(*args, **kwargs): + print("args", args) + print("kwargs", kwargs) + + def describe_args(*args, **kwargs): for value in args: print(f"{type(value).__name__}: {value}") diff --git a/tests/fixtures/scripts_project/pyproject.toml b/tests/fixtures/scripts_project/pyproject.toml index c32c9f3c6..da75cce24 100644 --- a/tests/fixtures/scripts_project/pyproject.toml +++ b/tests/fixtures/scripts_project/pyproject.toml @@ -99,6 +99,29 @@ greet = "pkg:greet" type = "boolean" + [tool.poe.tasks.multiple-value-args] + script = "pkg:echo_script(first, second, widgets=widgets, engines=engines)" + + [[tool.poe.tasks.multiple-value-args.args]] + name = "first" + positional = true + + [[tool.poe.tasks.multiple-value-args.args]] + name = "second" + positional = true + multiple = true + type = "integer" + + [[tool.poe.tasks.multiple-value-args.args]] + name = "widgets" + multiple = 2 + + [[tool.poe.tasks.multiple-value-args.args]] + name = "engines" + multiple = true + required = true + + [build-system] requires = ["poetry>=0.12"] build-backend = "poetry.masonry.api" From 72611ff546f97d1f42f5b07c57f2e8fe7a66c0be Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Mon, 6 Jun 2022 14:14:31 +0200 Subject: [PATCH 2/8] Fix bug when multiple=False --- poethepoet/task/args.py | 2 +- tests/test_cli.py | 46 +++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/poethepoet/task/args.py b/poethepoet/task/args.py index 1fd86da3c..bf3ff0a80 100644 --- a/poethepoet/task/args.py +++ b/poethepoet/task/args.py @@ -252,7 +252,7 @@ def _get_argument_params(self, arg: ArgParams): result["nargs"] = "+" else: result["nargs"] = "*" - elif isinstance(multiple, int): + elif multiple and isinstance(multiple, int): result["nargs"] = multiple if arg.get("positional", False): diff --git a/tests/test_cli.py b/tests/test_cli.py index b89d9faa7..30124fe3c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,5 @@ from poethepoet import __version__ +import re def test_call_no_args(run_poe): @@ -76,25 +77,26 @@ def test_documentation_of_task_named_args(run_poe): assert ( "\nResult: No task specified.\n" in result.capture ), "Output should include status message" - assert ( - "CONFIGURED TASKS\n" - " composite_task \n" - " echo-args \n" - " static-args-test \n" - " call_attrs \n" - " greet \n" - " greet-passed-args \n" - " --greeting \n" - " --user \n" - " --optional \n" - " --upper \n" - " greet-full-args \n" - " --greeting, -g \n" - " --user \n" - " --upper \n" - " --age, -a \n" - " --height, -h The user's height in meters\n" - " greet-strict All arguments are required\n" - " --greeting this one is required\n" - " --name and this one is required\n" - ) in result.capture + assert re.search( + r"CONFIGURED TASKS\n" + r" composite_task \s+\n" + r" echo-args \s+\n" + r" static-args-test \s+\n" + r" call_attrs \s+\n" + r" greet \s+\n" + r" greet-passed-args\s+\n" + r" --greeting \s+\n" + r" --user \s+\n" + r" --optional \s+\n" + r" --upper \s+\n" + r" greet-full-args \s+\n" + r" --greeting, -g \s+\n" + r" --user \s+\n" + r" --upper \s+\n" + r" --age, -a \s+\n" + r" --height, -h \s+The user's height in meters\n" + r" greet-strict \s+All arguments are required\n" + r" --greeting \s+this one is required\n" + r" --name \s+and this one is required\n", + result.capture, + ) From e1ea459342064328dc80fdc0c42abfd6e4ca017d Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Mon, 6 Jun 2022 21:49:55 +0200 Subject: [PATCH 3/8] Write tests for multiple args for script task --- tests/test_script_tasks.py | 92 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/test_script_tasks.py b/tests/test_script_tasks.py index 0496a73ea..a3cd5ace4 100644 --- a/tests/test_script_tasks.py +++ b/tests/test_script_tasks.py @@ -252,3 +252,95 @@ def test_script_with_positional_args_and_options(run_poe_subproc): assert result.capture == "Poe => greet-positional --upper help! Santa\n" assert result.stdout == "HELP! SANTA\n" assert result.stderr == "" + + +def test_script_with_multi_value_args(run_poe_subproc): + # Test with all args + result = run_poe_subproc( + "multiple-value-args", + "hey", + "1", + "2", + "3", + "--widgets", + "cow", + "dog", + "--engines", + "v2", + "v8", + project="scripts", + ) + assert ( + result.capture + == "Poe => multiple-value-args hey 1 2 3 --widgets cow dog --engines v2 v8\n" + ) + assert result.stdout == ( + "args ('hey', [1, 2, 3])\n" + "kwargs {'widgets': ['cow', 'dog'], 'engines': ['v2', 'v8']}\n" + ) + assert result.stderr == "" + + # Test with some args + result = run_poe_subproc( + "multiple-value-args", "1", "--engines", "v2", project="scripts" + ) + assert result.capture == "Poe => multiple-value-args 1 --engines v2\n" + assert result.stdout == ( + "args ('1', [])\nkwargs {'widgets': None, 'engines': ['v2']}\n" + ) + assert result.stderr == "" + + # Test with minimal args + result = run_poe_subproc( + "multiple-value-args", "--engines", "v2", project="scripts" + ) + assert result.capture == "Poe => multiple-value-args --engines v2\n" + assert result.stdout == ( + "args (None, [])\nkwargs {'widgets': None, 'engines': ['v2']}\n" + ) + assert result.stderr == "" + + # Not enough values for option: 0 + result = run_poe_subproc( + "multiple-value-args", "--widgets", "--engines", "v2", project="scripts" + ) + assert result.capture == "" + assert result.stdout == "" + assert ( + "poe multiple-value-args: error: argument --widgets: expected 2 arguments" + in result.stderr + ) + + # Too many values for option: 3 + result = run_poe_subproc( + "multiple-value-args", + "bloop", # without the first arg, dong gets read an positional + "--widgets", + "ding", + "dang", + "dong", + "--engines", + "v2", + project="scripts", + ) + assert result.capture == "" + assert result.stdout == "" + assert ( + "poe multiple-value-args: error: unrecognized arguments: dong" in result.stderr + ) + + # wrong type for multiple values + result = run_poe_subproc( + "multiple-value-args", + "1", + "wrong", + "--engines", + "v2", + project="scripts", + ) + assert result.capture == "" + assert result.stdout == "" + assert ( + "poe multiple-value-args: error: argument second: invalid int value: 'wrong'" + in result.stderr + ) From 515467eba145678c93448fadf6cb9e89c47f5048 Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Tue, 7 Jun 2022 23:44:49 +0200 Subject: [PATCH 4/8] Add basic tests for multiple args option for other task types Also progress a little further on reducing test dependency on echo and env --- tests/fixtures/cmds_project/pyproject.toml | 21 ++++++++-- .../default_value_project/pyproject.toml | 2 +- tests/fixtures/envfile_project/pyproject.toml | 4 +- tests/fixtures/includes_project/greet.toml | 8 ++-- tests/fixtures/includes_project/laugh.json | 4 +- .../includes_project/multiple_includes.toml | 2 +- .../fixtures/includes_project/pyproject.toml | 2 +- .../poe_test_helpers/__init__.py | 8 +++- .../fixtures/sequences_project/pyproject.toml | 21 ++++++++-- tests/fixtures/shells_project/pyproject.toml | 39 ++++++++++++++----- tests/test_cmd_tasks.py | 15 +++++-- tests/test_default_value.py | 7 +++- tests/test_envfile.py | 8 ++-- tests/test_includes.py | 10 ++--- tests/test_sequence_tasks.py | 20 ++++++++-- tests/test_shell_task.py | 36 ++++++++++++----- 16 files changed, 150 insertions(+), 57 deletions(-) diff --git a/tests/fixtures/cmds_project/pyproject.toml b/tests/fixtures/cmds_project/pyproject.toml index 7913a1517..bc6727f96 100644 --- a/tests/fixtures/cmds_project/pyproject.toml +++ b/tests/fixtures/cmds_project/pyproject.toml @@ -1,14 +1,27 @@ -tool.poe.tasks.show_env = "env" +tool.poe.tasks.show_env = "poe_test_env" [tool.poe.tasks.echo] -cmd = "echo POE_ROOT:$POE_ROOT ${BEST_PASSWORD}, task_args:" +cmd = "poe_test_echo POE_ROOT:$POE_ROOT ${BEST_PASSWORD}, task_args:" help = "It says what you say" env = { BEST_PASSWORD = "Password1" } [tool.poe.tasks.greet] -shell = "echo $formal_greeting $subject" +shell = "poe_test_echo $formal_greeting $subject" args = ["formal-greeting", "subject"] [tool.poe.tasks.surfin-bird] -cmd = "echo $WORD is the word" +cmd = "poe_test_echo $WORD is the word" env = { WORD = "${SOME_INPUT_VAR}"} + +[tool.poe.tasks.multiple-value-arg] +cmd = "poe_test_echo \"first: ${first} second: ${second}\"" + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "first" + positional = true + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "second" + positional = true + multiple = true + type = "integer" diff --git a/tests/fixtures/default_value_project/pyproject.toml b/tests/fixtures/default_value_project/pyproject.toml index 035c16869..edaa80226 100644 --- a/tests/fixtures/default_value_project/pyproject.toml +++ b/tests/fixtures/default_value_project/pyproject.toml @@ -7,7 +7,7 @@ FIVE.default = "nope" SIX.default = "!six!" [tool.poe.tasks.test] -cmd = "echo $ONE $TWO $THREE $FOUR $FIVE $SIX" +cmd = "poe_test_echo $ONE $TWO $THREE $FOUR $FIVE $SIX" env.TWO = "!two!" env.FIVE = "!five!" env.SIX.default = "nope" diff --git a/tests/fixtures/envfile_project/pyproject.toml b/tests/fixtures/envfile_project/pyproject.toml index e77d2c213..9dd6e1985 100644 --- a/tests/fixtures/envfile_project/pyproject.toml +++ b/tests/fixtures/envfile_project/pyproject.toml @@ -4,12 +4,12 @@ env = { HOST = "${HOST}:80" } [tool.poe.tasks.deploy-dev] cmd = """ -echo "deploying to ${USER}:${PASSWORD}@${HOST}${PATH_SUFFIX}" +poe_test_echo "deploying to ${USER}:${PASSWORD}@${HOST}${PATH_SUFFIX}" """ env = { HOST = "${HOST}80" } # reference and override value from envfile [tool.poe.tasks.deploy-prod] cmd = """ -echo "deploying to ${USER}:${PASSWORD}@${HOST}${PATH_SUFFIX}" +poe_test_echo "deploying to ${USER}:${PASSWORD}@${HOST}${PATH_SUFFIX}" """ envfile = "prod.env" diff --git a/tests/fixtures/includes_project/greet.toml b/tests/fixtures/includes_project/greet.toml index 1cc20ea94..d5a4dab57 100644 --- a/tests/fixtures/includes_project/greet.toml +++ b/tests/fixtures/includes_project/greet.toml @@ -2,12 +2,12 @@ default_greeting = "Hello" [tool.poe.tasks] -echo.cmd = "echo echo echo" +echo.cmd = "poe_test_echo echo echo" echo.help = "This is ignored becuase it's already defined!" -greet = "echo $default_greeting" +greet = "poe_test_echo $default_greeting" -greet1 = "echo Hoi" +greet1 = "poe_test_echo Hoi" -greet2.cmd = "echo Hola" +greet2.cmd = "poe_test_echo Hola" greet2.help = "Issue a greeting from the Iberian Peninsula" diff --git a/tests/fixtures/includes_project/laugh.json b/tests/fixtures/includes_project/laugh.json index 72eba6a9d..d541518da 100644 --- a/tests/fixtures/includes_project/laugh.json +++ b/tests/fixtures/includes_project/laugh.json @@ -4,11 +4,11 @@ "envfile": "some_vars.env", "tasks": { "laugh": { - "shell": "echo $ONE_LAUGH | tr a-z A-Z", + "shell": "poe_test_echo $ONE_LAUGH | tr a-z A-Z", "help": "a mirthful task" }, "echo": { - "shell": "echo echo echo", + "shell": "poe_test_echo echo echo", "help": "This is ignored becuase it's already defined!" } } diff --git a/tests/fixtures/includes_project/multiple_includes.toml b/tests/fixtures/includes_project/multiple_includes.toml index 50fd9dd4c..d5946dd09 100644 --- a/tests/fixtures/includes_project/multiple_includes.toml +++ b/tests/fixtures/includes_project/multiple_includes.toml @@ -2,5 +2,5 @@ include = ["greet.toml", "laugh.json"] [tool.poe.tasks.echo] -cmd = "echo" +cmd = "poe_test_echo" help = "says what you say" diff --git a/tests/fixtures/includes_project/pyproject.toml b/tests/fixtures/includes_project/pyproject.toml index 081e9fa45..00113924f 100644 --- a/tests/fixtures/includes_project/pyproject.toml +++ b/tests/fixtures/includes_project/pyproject.toml @@ -3,5 +3,5 @@ include = "greet.toml" [tool.poe.tasks.echo] -cmd = "echo" +cmd = "poe_test_echo" help = "says what you say" diff --git a/tests/fixtures/packages/poe_test_helpers/poe_test_helpers/__init__.py b/tests/fixtures/packages/poe_test_helpers/poe_test_helpers/__init__.py index 761e703a3..a87d0695a 100644 --- a/tests/fixtures/packages/poe_test_helpers/poe_test_helpers/__init__.py +++ b/tests/fixtures/packages/poe_test_helpers/poe_test_helpers/__init__.py @@ -3,9 +3,15 @@ def echo(): - print(sys.argv[1:]) + """ + Imitates the basic usage of the standard echo command for cross platform usage + """ + print(" ".join(sys.argv[1:])) def env(): + """ + Imitates the basic usage of the standard env command for cross platform usage + """ for key, value in os.environ.items(): print(f"{key}={value}") diff --git a/tests/fixtures/sequences_project/pyproject.toml b/tests/fixtures/sequences_project/pyproject.toml index f7db17440..940989b14 100644 --- a/tests/fixtures/sequences_project/pyproject.toml +++ b/tests/fixtures/sequences_project/pyproject.toml @@ -1,12 +1,12 @@ [tool.poe.tasks] -part1 = "echo 'Hello'" -_part2.cmd = "echo '${SUBJECT}!'" +part1 = "poe_test_echo 'Hello'" +_part2.cmd = "poe_test_echo '${SUBJECT}!'" _part2.env = { SUBJECT = "World" } composite_task.sequence = [ ["part1", "_part2"], # wrapping in arrays means we can have different types of task in the sequence - [{cmd = "echo '${SMILEY}!'"}] + [{cmd = "poe_test_echo '${SMILEY}!'"}] ] # env var is inherited by subtask composite_task.env = { SMILEY = ":)" } @@ -20,6 +20,19 @@ greet-multiple.args = ["mouse"] travel = [ - { cmd = "echo 'from $PLANET to'" }, + { cmd = "poe_test_echo 'from $PLANET to'" }, { script = "my_package:print_var('DEST')" } ] + +[tool.poe.tasks.multiple-value-arg] +sequence = [{ cmd = "poe_test_echo first: ${first}" }, { cmd = " poe_test_echo second: ${second}" }] + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "first" + positional = true + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "second" + positional = true + multiple = true + type = "integer" diff --git a/tests/fixtures/shells_project/pyproject.toml b/tests/fixtures/shells_project/pyproject.toml index c78224213..b0dd9dfb1 100644 --- a/tests/fixtures/shells_project/pyproject.toml +++ b/tests/fixtures/shells_project/pyproject.toml @@ -2,36 +2,36 @@ tool.poe.default_task_type = "shell" [tool.poe.tasks] -count = "echo 1 && echo 2 && echo $(python -c 'print(1 + 2)')" +count = "poe_test_echo 1 && poe_test_echo 2 && poe_test_echo $(python -c 'print(1 + 2)')" sing = """ -echo "this is the story"; -echo "all about how" && # the last line won't run -echo "my life got flipped; +poe_test_echo "this is the story"; +poe_test_echo "all about how" && # the last line won't run +poe_test_echo "my life got flipped; turned upside down" || -echo "bam bam baaam bam" +poe_test_echo "bam bam baaam bam" """ [tool.poe.tasks.greet] -shell = "echo $formal_greeting $subject" +shell = "poe_test_echo $formal_greeting $subject" args = ["formal-greeting", "subject"] [tool.poe.tasks.echo_sh] interpreter = ["sh"] -shell = "echo $0 $test_var" +shell = "poe_test_echo $0 $test_var" env = { test_var = "roflcopter"} [tool.poe.tasks.echo_bash] interpreter = "bash" -shell = "echo $0 $test_var" +shell = "poe_test_echo $0 $test_var" env = { test_var = "roflcopter"} [tool.poe.tasks.echo_pwsh] interpreter = "pwsh" -shell = "echo $ENV:test_var" +shell = "poe_test_echo $ENV:test_var" env = { test_var = "roflcopter"} @@ -42,3 +42,24 @@ import sys, os print(sys.version_info, os.environ.get("test_var")) """ env = { test_var = "roflcopter"} + + +[tool.poe.tasks.multiple-value-arg] +shell = """ +poe_test_echo "first: ${first} second: ${second}" + +# bash treats space delimited string like array for iteration! +for word in $second; do + poe_test_echo $word +done +""" + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "first" + positional = true + + [[tool.poe.tasks.multiple-value-arg.args]] + name = "second" + positional = true + multiple = true + type = "integer" diff --git a/tests/test_cmd_tasks.py b/tests/test_cmd_tasks.py index 4044c3329..48939a735 100644 --- a/tests/test_cmd_tasks.py +++ b/tests/test_cmd_tasks.py @@ -2,7 +2,7 @@ def test_call_echo_task(run_poe_subproc, projects, esc_prefix): result = run_poe_subproc("echo", "foo", "!", project="cmds") assert ( result.capture - == f"Poe => echo POE_ROOT:{projects['cmds']} Password1, task_args: foo !\n" + == f"Poe => poe_test_echo POE_ROOT:{projects['cmds']} Password1, task_args: foo !\n" ) assert result.stdout == f"POE_ROOT:{projects['cmds']} Password1, task_args: foo !\n" assert result.stderr == "" @@ -10,7 +10,7 @@ def test_call_echo_task(run_poe_subproc, projects, esc_prefix): def test_setting_envvar_in_task(run_poe_subproc, projects): result = run_poe_subproc("show_env", project="cmds") - assert result.capture == f"Poe => env\n" + assert result.capture == f"Poe => poe_test_env\n" assert f"POE_ROOT={projects['cmds']}" in result.stdout assert result.stderr == "" @@ -19,7 +19,7 @@ def test_cmd_task_with_dash_case_arg(run_poe_subproc): result = run_poe_subproc( "greet", "--formal-greeting=hey", "--subject=you", project="cmds" ) - assert result.capture == f"Poe => echo $formal_greeting $subject\n" + assert result.capture == f"Poe => poe_test_echo $formal_greeting $subject\n" assert result.stdout == "hey you\n" assert result.stderr == "" @@ -28,6 +28,13 @@ def test_cmd_alias_env_var(run_poe_subproc): result = run_poe_subproc( "surfin-bird", project="cmds", env={"SOME_INPUT_VAR": "BIRD"} ) - assert result.capture == f"Poe => echo BIRD is the word\n" + assert result.capture == f"Poe => poe_test_echo BIRD is the word\n" assert result.stdout == "BIRD is the word\n" assert result.stderr == "" + + +def test_cmd_multiple_value_arg(run_poe_subproc): + result = run_poe_subproc("multiple-value-arg", "hey", "1", "2", "3", project="cmds") + assert result.capture == "Poe => poe_test_echo first: hey second: 1 2 3\n" + assert result.stdout == "first: hey second: 1 2 3\n" + assert result.stderr == "" diff --git a/tests/test_default_value.py b/tests/test_default_value.py index 3a85bdc0e..568a31467 100644 --- a/tests/test_default_value.py +++ b/tests/test_default_value.py @@ -1,6 +1,9 @@ def test_global_envfile_and_default(run_poe_subproc): result = run_poe_subproc("test", project="default_value") - assert "Poe => echo !one! !two! !three! !four! !five! !six!\n" in result.capture + assert ( + "Poe => poe_test_echo !one! !two! !three! !four! !five! !six!\n" + in result.capture + ) assert result.stdout == "!one! !two! !three! !four! !five! !six!\n" assert result.stderr == "" @@ -16,6 +19,6 @@ def test_global_envfile_and_default_with_presets(run_poe_subproc): } result = run_poe_subproc("test", project="default_value", env=env) - assert "Poe => echo !one! !two! !three! 444 !five! 666\n" in result.capture + assert "Poe => poe_test_echo !one! !two! !three! 444 !five! 666\n" in result.capture assert result.stdout == "!one! !two! !three! 444 !five! 666\n" assert result.stderr == "" diff --git a/tests/test_envfile.py b/tests/test_envfile.py index 445ca406a..367db5e54 100644 --- a/tests/test_envfile.py +++ b/tests/test_envfile.py @@ -8,14 +8,14 @@ def test_global_envfile_and_default(run_poe_subproc, is_windows): if is_windows: # On windows shlex works in non-POSIX mode which results in quotes assert ( - 'Poe => echo "deploying to admin:12345@dev.example.com:8080"\n' + 'Poe => poe_test_echo "deploying to admin:12345@dev.example.com:8080"\n' in result.capture ) assert result.stdout == '"deploying to admin:12345@dev.example.com:8080"\n' assert result.stderr == "" else: assert ( - "Poe => echo deploying to admin:12345@dev.example.com:8080\n" + "Poe => poe_test_echo deploying to admin:12345@dev.example.com:8080\n" in result.capture ) assert result.stdout == "deploying to admin:12345@dev.example.com:8080\n" @@ -26,14 +26,14 @@ def test_task_envfile_and_default(run_poe_subproc, is_windows): result = run_poe_subproc("deploy-prod", project="envfile") if is_windows: assert ( - 'Poe => echo "deploying to admin:12345@prod.example.com/app"\n' + 'Poe => poe_test_echo "deploying to admin:12345@prod.example.com/app"\n' in result.capture ) assert result.stdout == '"deploying to admin:12345@prod.example.com/app"\n' assert result.stderr == "" else: assert ( - "Poe => echo deploying to admin:12345@prod.example.com/app\n" + "Poe => poe_test_echo deploying to admin:12345@prod.example.com/app\n" in result.capture ) assert result.stdout == "deploying to admin:12345@prod.example.com/app\n" diff --git a/tests/test_includes.py b/tests/test_includes.py index 473860d30..fc85fd7b5 100644 --- a/tests/test_includes.py +++ b/tests/test_includes.py @@ -13,14 +13,14 @@ def test_docs_for_include_toml_file(run_poe_subproc): def test_run_task_included_from_toml_file(run_poe_subproc): result = run_poe_subproc("greet", "Whirl!", project="includes") - assert result.capture == "Poe => echo Hello Whirl!\n" + assert result.capture == "Poe => poe_test_echo Hello Whirl!\n" assert result.stdout == "Hello Whirl!\n" assert result.stderr == "" def test_run_task_not_included_from_toml_file(run_poe_subproc): result = run_poe_subproc("echo", "Whirl!", project="includes") - assert result.capture == "Poe => echo Whirl!\n" + assert result.capture == "Poe => poe_test_echo Whirl!\n" assert result.stdout == "Whirl!\n" assert result.stderr == "" @@ -48,21 +48,21 @@ def test_running_from_multiple_includes(run_poe_subproc, projects): "Whirl!", project="includes", ) - assert result.capture == "Poe => echo Whirl!\n" + assert result.capture == "Poe => poe_test_echo Whirl!\n" assert result.stdout == "Whirl!\n" assert result.stderr == "" result = run_poe_subproc( f'--root={projects["includes/multiple_includes"]}', "greet", "Whirl!" ) - assert result.capture == "Poe => echo Hello Whirl!\n" + assert result.capture == "Poe => poe_test_echo Hello Whirl!\n" assert result.stdout == "Hello Whirl!\n" assert result.stderr == "" result = run_poe_subproc( f'--root={projects["includes/multiple_includes"]}', "laugh" ) - assert result.capture == "Poe => echo $ONE_LAUGH | tr a-z A-Z\n" + assert result.capture == "Poe => poe_test_echo $ONE_LAUGH | tr a-z A-Z\n" assert result.stdout == "LOL\n" assert result.stderr == "" diff --git a/tests/test_sequence_tasks.py b/tests/test_sequence_tasks.py index 4f8ae0911..94a8717d1 100644 --- a/tests/test_sequence_tasks.py +++ b/tests/test_sequence_tasks.py @@ -4,13 +4,13 @@ def test_sequence_task(run_poe_subproc, esc_prefix, is_windows): # On windows shlex works in non-POSIX mode which results in quotes assert ( result.capture - == f"Poe => echo 'Hello'\nPoe => echo 'World!'\nPoe => echo ':)!'\n" + == f"Poe => poe_test_echo 'Hello'\nPoe => poe_test_echo 'World!'\nPoe => poe_test_echo ':)!'\n" ) assert result.stdout == f"'Hello'\n'World!'\n':)!'\n" else: assert ( result.capture - == f"Poe => echo Hello\nPoe => echo World!\nPoe => echo :)!\n" + == f"Poe => poe_test_echo Hello\nPoe => poe_test_echo World!\nPoe => poe_test_echo :)!\n" ) assert result.stdout == f"Hello\nWorld!\n:)!\n" assert result.stderr == "" @@ -23,13 +23,13 @@ def test_another_sequence_task(run_poe_subproc, esc_prefix, is_windows): # On windows shlex works in non-POSIX mode which results in quotes assert ( result.capture - == f"Poe => echo 'Hello'\nPoe => echo 'World!'\nPoe => echo ':)!'\n" + == f"Poe => poe_test_echo 'Hello'\nPoe => poe_test_echo 'World!'\nPoe => poe_test_echo ':)!'\n" ) assert result.stdout == f"'Hello'\n'World!'\n':)!'\n" else: assert ( result.capture - == f"Poe => echo Hello\nPoe => echo World!\nPoe => echo :)!\n" + == f"Poe => poe_test_echo Hello\nPoe => poe_test_echo World!\nPoe => poe_test_echo :)!\n" ) assert result.stdout == f"Hello\nWorld!\n:)!\n" assert result.stderr == "" @@ -44,3 +44,15 @@ def test_a_script_sequence_task_with_args(run_poe_subproc, esc_prefix): ) assert result.stdout == f"hello Tom\nhello Jerry\n" assert result.stderr == "" + + +def test_cmd_multiple_value_arg(run_poe_subproc): + result = run_poe_subproc( + "multiple-value-arg", "hey", "1", "2", "3", project="sequences" + ) + assert ( + result.capture + == "Poe => poe_test_echo first: hey\nPoe => poe_test_echo second: 1 2 3\n" + ) + assert result.stdout == "first: hey\nsecond: 1 2 3\n" + assert result.stderr == "" diff --git a/tests/test_shell_task.py b/tests/test_shell_task.py index 5e59f6eef..54921fe97 100644 --- a/tests/test_shell_task.py +++ b/tests/test_shell_task.py @@ -6,7 +6,7 @@ def test_shell_task(run_poe_subproc): result = run_poe_subproc("count", project="shells") assert ( result.capture - == f"Poe => echo 1 && echo 2 && echo $(python -c 'print(1 + 2)')\n" + == f"Poe => poe_test_echo 1 && poe_test_echo 2 && poe_test_echo $(python -c 'print(1 + 2)')\n" ) assert result.stdout == "1\n2\n3\n" assert result.stderr == "" @@ -23,10 +23,10 @@ def test_multiline_non_default_type_task(run_poe_subproc): # This should be exactly the same as calling the echo task directly result = run_poe_subproc("sing", project="shells") assert result.capture == ( - f'Poe => echo "this is the story";\n' - 'echo "all about how" && # the last line won\'t run\n' - 'echo "my life got flipped;\n' - ' turned upside down" ||\necho "bam bam baaam bam"\n' + f'Poe => poe_test_echo "this is the story";\n' + 'poe_test_echo "all about how" && # the last line won\'t run\n' + 'poe_test_echo "my life got flipped;\n' + ' turned upside down" ||\npoe_test_echo "bam bam baaam bam"\n' ) assert result.stdout == ( f"this is the story\n" @@ -41,7 +41,7 @@ def test_shell_task_with_dash_case_arg(run_poe_subproc): result = run_poe_subproc( "greet", "--formal-greeting=hey", "--subject=you", project="shells" ) - assert result.capture == (f"Poe => echo $formal_greeting $subject\n") + assert result.capture == (f"Poe => poe_test_echo $formal_greeting $subject\n") assert result.stdout == "hey you\n" assert result.stderr == "" @@ -49,7 +49,7 @@ def test_shell_task_with_dash_case_arg(run_poe_subproc): @pytest.mark.skipif(not shutil.which("sh"), reason="No sh available") def test_interpreter_sh(run_poe_subproc): result = run_poe_subproc("echo_sh", project="shells") - assert result.capture == (f"Poe => echo $0 $test_var\n") + assert result.capture == (f"Poe => poe_test_echo $0 $test_var\n") assert "roflcopter" in result.stdout assert result.stderr == "" @@ -57,7 +57,7 @@ def test_interpreter_sh(run_poe_subproc): @pytest.mark.skipif(not shutil.which("bash"), reason="No bash available") def test_interpreter_bash(run_poe_subproc): result = run_poe_subproc("echo_bash", project="shells") - assert result.capture == (f"Poe => echo $0 $test_var\n") + assert result.capture == (f"Poe => poe_test_echo $0 $test_var\n") assert "bash" in result.stdout assert "roflcopter" in result.stdout assert result.stderr == "" @@ -66,7 +66,7 @@ def test_interpreter_bash(run_poe_subproc): @pytest.mark.skipif(not shutil.which("pwsh"), reason="No powershell available") def test_interpreter_pwsh(run_poe_subproc, is_windows): result = run_poe_subproc("echo_pwsh", project="shells") - assert result.capture == (f"Poe => echo $ENV:test_var\n") + assert result.capture == (f"Poe => poe_test_echo $ENV:test_var\n") assert "roflcopter" in result.stdout assert result.stderr == "" @@ -103,3 +103,21 @@ def test_global_interpreter_config(run_poe_subproc, projects): assert result.capture == (f"Poe => import sys\nprint(sys.version_info)\n") assert result.stdout.startswith("sys.version_info(major=3,") assert result.stderr == "" + + +def test_cmd_multiple_value_arg(run_poe_subproc): + result = run_poe_subproc( + "multiple-value-arg", "hey", "1", "2", "3", project="shells" + ) + assert ( + result.capture + == """Poe => poe_test_echo "first: ${first} second: ${second}" + +# bash treats space delimited string like array for iteration! +for word in $second; do + poe_test_echo $word +done +""" + ) + assert result.stdout == "first: hey second: 1 2 3\n1\n2\n3\n" + assert result.stderr == "" From b8f82cba6862a135a0571a8732ab59e457b5fc86 Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Fri, 10 Jun 2022 22:29:34 +0200 Subject: [PATCH 5/8] Update ci config --- .github/workflows/ci.yml | 67 +++++++++++++--------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 862eda15e..1cfa71f40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,27 +5,18 @@ on: [push, pull_request] jobs: code-quality: - runs-on: ubuntu-latest - name: Check coding standards - + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - uses: actions/cache@v2 - with: - path: ~/.cache/pypoetry/virtualenvs - key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- + - uses: actions/checkout@v3 - name: Install poetry - shell: bash - run: | - python -m pip install poetry - echo "$HOME/.poetry/bin" >> $GITHUB_PATH + run: pipx install poetry + + - uses: actions/setup-python@v4 + with: + python-version: 3.9 + cache: poetry - name: Install dependencies run: poetry install @@ -43,32 +34,22 @@ jobs: run: poetry run poe check-docs run-tests: - runs-on: ${{ matrix.os }}-latest - name: Run tests - strategy: matrix: os: [Ubuntu, MacOS, Windows] python-version: ['3.7', '3.8', '3.9', '3.10'] - + runs-on: ${{ matrix.os }}-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: ${{ matrix.python-version }} - - uses: actions/cache@v2 - with: - path: ~/.cache/pypoetry/virtualenvs - key: ${{ runner.os }}-poetry-${{ hashFiles('poetry.lock') }} - restore-keys: | - ${{ runner.os }}-poetry- + - uses: actions/checkout@v3 - name: Install poetry - shell: bash - run: | - python -m pip install poetry - echo "$HOME/.poetry/bin" >> $GITHUB_PATH + run: pipx install poetry + + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: poetry - name: Install dependencies run: poetry install @@ -77,20 +58,16 @@ jobs: run: poetry run pytest -v build-release: + name: Build and release runs-on: ubuntu-latest needs: [code-quality, run-tests] - steps: - - uses: actions/checkout@v2 - - uses: actions/setup-python@v2 - with: - python-version: 3.7 - + - uses: actions/checkout@v3 - name: Install poetry - shell: bash - run: | - python -m pip install poetry - echo "$HOME/.poetry/bin" >> $GITHUB_PATH + run: pipx install poetry + - uses: actions/setup-python@v4 + with: + python-version: 3.9 - name: Build package run: poetry build From 20814f752eb16fa17db053f62c31c61203a93e5c Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Fri, 10 Jun 2022 22:54:14 +0200 Subject: [PATCH 6/8] Disallow configuration of boolean args with multiple values --- .github/workflows/ci.yml | 2 ++ poethepoet/task/args.py | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1cfa71f40..21a6ed1c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,8 +63,10 @@ jobs: needs: [code-quality, run-tests] steps: - uses: actions/checkout@v3 + - name: Install poetry run: pipx install poetry + - uses: actions/setup-python@v4 with: python-version: 3.9 diff --git a/poethepoet/task/args.py b/poethepoet/task/args.py index bf3ff0a80..e2102316c 100644 --- a/poethepoet/task/args.py +++ b/poethepoet/task/args.py @@ -208,6 +208,11 @@ def _validate_params( f"The multiple option for arg {arg_name!r} of {task_name!r}" " must be given a boolean or integer >= 2" ) + if multiple is not False and params.get("type") == "boolean": + return ( + "Incompatible param 'multiple' for arg {arg_name!r} of {task_name!r} " + "with type: 'boolean'" + ) return None From 798688ea020429cfa0e75d23ab2c1227ca9f7372 Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Fri, 10 Jun 2022 22:56:08 +0200 Subject: [PATCH 7/8] Write readme section for multiple option & make tests work better on windows --- README.rst | 25 +++++++++++++++++++ tests/fixtures/example_project/pyproject.toml | 12 ++++----- tests/fixtures/graphs_project/pyproject.toml | 11 ++++---- tests/fixtures/high_verbosity/pyproject.toml | 2 +- tests/fixtures/low_verbosity/pyproject.toml | 2 +- .../empty_prefix/pyproject.toml | 2 +- .../poetry_plugin_project/pyproject.toml | 2 +- tests/fixtures/scripts_project/pyproject.toml | 2 +- tests/test_cli.py | 2 +- tests/test_cmd_tasks.py | 10 +++++--- tests/test_graph_execution.py | 4 +-- tests/test_poe_config.py | 17 +++++++++---- tests/test_poetry_plugin.py | 4 +-- tests/test_sequence_tasks.py | 2 +- tests/test_shell_task.py | 2 +- tests/test_task_running.py | 2 +- 16 files changed, 68 insertions(+), 33 deletions(-) diff --git a/README.rst b/README.rst index f1cab8c8e..ff150241b 100644 --- a/README.rst +++ b/README.rst @@ -566,6 +566,31 @@ Named arguments support the following configuration options: If set to true then the argument becomes a position argument instead of an option argument. Note that positional arguments may not have type *bool*. +- **multiple** : Union[bool, int] + If the multiple option is set to true on a positional or option argument then that + argument will accept multiple values. + + If set to a number, then the argument will accept exactly that number of values. + + For positional aguments, only the last positional argument may have the multiple + option set. + + The multiple option is not compatible with arguments with type boolean since + these are interpreted as flags. However multiple ones or zeros can be passed to an + argument of type "integer" for similar effect. + + The values provided to an argument with the multiple option set are available on + the environment as a string of whitespace separated values. For script tasks, the + values will be provided to your python function as a list of values. In a cmd task + the values can be passed as separate arugments to the task via templating as in the + following example. + + .. code-block:: toml + + [tool.poe.tasks.save] + cmd = "echo ${FILE_PATHS}" + args = [{ name = "FILE_PATHS", positional = true, multiple = true }] + - **required** : bool If true then not providing the argument will result in an error. Arguments are not required by default. diff --git a/tests/fixtures/example_project/pyproject.toml b/tests/fixtures/example_project/pyproject.toml index b01b39a47..82d15b891 100644 --- a/tests/fixtures/example_project/pyproject.toml +++ b/tests/fixtures/example_project/pyproject.toml @@ -14,13 +14,13 @@ env.DEST = "MARS" [tool.poe.tasks.echo] -cmd = "echo POE_ROOT:$POE_ROOT ${BEST_PASSWORD}, task_args:" +cmd = "poe_test_echo POE_ROOT:$POE_ROOT ${BEST_PASSWORD}, task_args:" help = "It says what you say" env = { BEST_PASSWORD = "Password1" } [tool.poe.tasks] -show_env = "env" +show_env = "poe_test_env" greet = { script = "dummy_package:main" } greet-shouty = { script = "dummy_package:main(upper=True)" } @@ -37,13 +37,13 @@ echo "my life got flipped; echo "bam bam baaam bam" """ -part1 = "echo 'Hello'" -_part2.cmd = "echo '${SUBJECT}!'" +part1 = "poe_test_echo 'Hello'" +_part2.cmd = "poe_test_echo '${SUBJECT}!'" _part2.env = { SUBJECT = "World" } composite_task.sequence = [ ["part1", "_part2"], # wrapping in arrays means we can have different types of task in the sequence - [{cmd = "echo '${SMILEY}!'"}] + [{cmd = "poe_test_echo '${SMILEY}!'"}] ] # env var is inherited by subtask composite_task.env = { SMILEY = ":)" } @@ -54,7 +54,7 @@ greet-multiple.sequence = ["dummy_package:main('Tom')", "dummy_package:main('Jer greet-multiple.default_item_type = "script" travel = [ - { cmd = "echo 'from $PLANET to'" }, + { cmd = "poe_test_echo 'from $PLANET to'" }, { script = "dummy_package:print_var('DEST')" } ] diff --git a/tests/fixtures/graphs_project/pyproject.toml b/tests/fixtures/graphs_project/pyproject.toml index b975cd71a..548d2e199 100644 --- a/tests/fixtures/graphs_project/pyproject.toml +++ b/tests/fixtures/graphs_project/pyproject.toml @@ -3,18 +3,17 @@ greet = "echo hello" _noop.shell = ":" -_about = "echo about" -_do_setup = "echo here we go..." - +_about = "echo about" +_do_setup = "echo here we go..." [tool.poe.tasks.think] - cmd = "echo Thinking $first_thing and $subject2" + shell = "echo Thinking $first_thing and $subject2" deps = ["_noop", "_do_setup"] uses = { first_thing = "_about $subject1" } args = [{ name = "subject1", positional = true }, { name = "subject2", positional = true }] [tool.poe.tasks.deep-graph-with-args] - cmd = "echo $greeting1 and $greeting2" + shell = "echo $greeting1 and $greeting2" deps = ["_do_setup", "think $subject1 $subject2"] - uses = { greeting1 = "greet $subject1", greeting2 = "greet $subject2"} + uses = { "greeting1" = "greet $subject1", greeting2 = "greet $subject2"} args = ["subject1", "subject2"] diff --git a/tests/fixtures/high_verbosity/pyproject.toml b/tests/fixtures/high_verbosity/pyproject.toml index c226261da..507a3fdd9 100644 --- a/tests/fixtures/high_verbosity/pyproject.toml +++ b/tests/fixtures/high_verbosity/pyproject.toml @@ -2,4 +2,4 @@ verbosity = 1 [tool.poe.tasks] -test = "echo Hello there!" +test = "poe_test_echo Hello there!" diff --git a/tests/fixtures/low_verbosity/pyproject.toml b/tests/fixtures/low_verbosity/pyproject.toml index 7592e8db4..1294cd72d 100644 --- a/tests/fixtures/low_verbosity/pyproject.toml +++ b/tests/fixtures/low_verbosity/pyproject.toml @@ -2,4 +2,4 @@ verbosity = -1 [tool.poe.tasks] -test = "echo Hello there!" +test = "poe_test_echo Hello there!" diff --git a/tests/fixtures/poetry_plugin_project/empty_prefix/pyproject.toml b/tests/fixtures/poetry_plugin_project/empty_prefix/pyproject.toml index e349d0588..9dd7d00f6 100644 --- a/tests/fixtures/poetry_plugin_project/empty_prefix/pyproject.toml +++ b/tests/fixtures/poetry_plugin_project/empty_prefix/pyproject.toml @@ -14,7 +14,7 @@ cowsay = "../../packages/python_cowsay-1.0.1-py3-none-any.whl" poetry_command = "" [tool.poe.tasks] -echo = { cmd = "echo", help = "It's like echo"} +echo = { cmd = "poe_test_echo", help = "It's like echo"} cow-greet = "cowsay 'good day sir!'" [build-system] diff --git a/tests/fixtures/poetry_plugin_project/pyproject.toml b/tests/fixtures/poetry_plugin_project/pyproject.toml index 29b0eb231..3a32b53d5 100644 --- a/tests/fixtures/poetry_plugin_project/pyproject.toml +++ b/tests/fixtures/poetry_plugin_project/pyproject.toml @@ -15,7 +15,7 @@ pre_env_info = "echo 'THIS IS YOUR ENV!'" post_env_info = "echo 'THAT WAS YOUR ENV!'" [tool.poe.tasks] -echo = { cmd = "echo", help = "It's like echo"} +echo = { cmd = "poe_test_echo", help = "It's like echo"} cow-greet = "cowsay 'good day sir!'" cow-cheese.shell = "import cowsay; print(list(cowsay.char_names)[1])" cow-cheese.interpreter = "python" diff --git a/tests/fixtures/scripts_project/pyproject.toml b/tests/fixtures/scripts_project/pyproject.toml index da75cce24..f6cf8d4d3 100644 --- a/tests/fixtures/scripts_project/pyproject.toml +++ b/tests/fixtures/scripts_project/pyproject.toml @@ -14,7 +14,7 @@ default_array_item_task_type = "cmd" [tool.poe.tasks] # Interpret subtasks as cmd instead of ref -composite_task = ["echo Hello", "echo World!"] +composite_task = ["poe_test_echo Hello", "poe_test_echo World!"] # test_setting_default_task_type echo-args = "pkg:echo_args" diff --git a/tests/test_cli.py b/tests/test_cli.py index 30124fe3c..837f919b0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -64,7 +64,7 @@ def test_version_option(run_poe): def test_dry_run(run_poe_subproc): result = run_poe_subproc("-d", "show_env") - assert result.capture == f"Poe => env\n" + assert result.capture == f"Poe => poe_test_env\n" assert result.stdout == "" assert result.stderr == "" diff --git a/tests/test_cmd_tasks.py b/tests/test_cmd_tasks.py index 48939a735..3db087703 100644 --- a/tests/test_cmd_tasks.py +++ b/tests/test_cmd_tasks.py @@ -33,8 +33,12 @@ def test_cmd_alias_env_var(run_poe_subproc): assert result.stderr == "" -def test_cmd_multiple_value_arg(run_poe_subproc): +def test_cmd_task_with_multiple_value_arg(run_poe_subproc, is_windows): result = run_poe_subproc("multiple-value-arg", "hey", "1", "2", "3", project="cmds") - assert result.capture == "Poe => poe_test_echo first: hey second: 1 2 3\n" - assert result.stdout == "first: hey second: 1 2 3\n" + if is_windows: + assert result.capture == 'Poe => poe_test_echo "first: hey second: 1 2 3"\n' + assert result.stdout == '"first: hey second: 1 2 3\n"' + else: + assert result.capture == "Poe => poe_test_echo first: hey second: 1 2 3\n" + assert result.stdout == "first: hey second: 1 2 3\n" assert result.stderr == "" diff --git a/tests/test_graph_execution.py b/tests/test_graph_execution.py index 195c53d0c..982ad8a2b 100644 --- a/tests/test_graph_execution.py +++ b/tests/test_graph_execution.py @@ -5,8 +5,8 @@ def test_call_attr_func(run_poe_subproc): "Poe => :\n" "Poe <= echo about\n" "Poe <= echo hello\n" - "Poe => echo Thinking about and\n" - "Poe => echo hello and hello\n" + "Poe => echo Thinking $first_thing and $subject2\n" + "Poe => echo $greeting1 and $greeting2\n" ) assert result.stdout == ( "here we go...\n" "Thinking about and\n" "hello and hello\n" diff --git a/tests/test_poe_config.py b/tests/test_poe_config.py index 40d5371ef..e9346ff4b 100644 --- a/tests/test_poe_config.py +++ b/tests/test_poe_config.py @@ -18,7 +18,9 @@ def test_setting_default_task_type(run_poe_subproc, projects, esc_prefix): def test_setting_default_array_item_task_type(run_poe_subproc): result = run_poe_subproc("composite_task", project="scripts") - assert result.capture == f"Poe => echo Hello\nPoe => echo World!\n" + assert ( + result.capture == f"Poe => poe_test_echo Hello\nPoe => poe_test_echo World!\n" + ) assert result.stdout == f"Hello\nWorld!\n" assert result.stderr == "" @@ -26,10 +28,15 @@ def test_setting_default_array_item_task_type(run_poe_subproc): def test_setting_global_env_vars(run_poe_subproc, is_windows): result = run_poe_subproc("travel") if is_windows: - assert result.capture == f"Poe => echo 'from EARTH to'\nPoe => travel[1]\n" + assert ( + result.capture + == f"Poe => poe_test_echo 'from EARTH to'\nPoe => travel[1]\n" + ) assert result.stdout == f"'from EARTH to'\nMARS\n" else: - assert result.capture == f"Poe => echo from EARTH to\nPoe => travel[1]\n" + assert ( + result.capture == f"Poe => poe_test_echo from EARTH to\nPoe => travel[1]\n" + ) assert result.stdout == f"from EARTH to\nMARS\n" assert result.stderr == "" @@ -51,7 +58,7 @@ def test_override_default_verbosity(run_poe_subproc, low_verbosity_project_path) "test", cwd=low_verbosity_project_path, ) - assert result.capture == "Poe => echo Hello there!\n" + assert result.capture == "Poe => poe_test_echo Hello there!\n" assert result.stdout == "Hello there!\n" assert result.stderr == "" @@ -62,7 +69,7 @@ def test_partially_decrease_verbosity(run_poe_subproc, high_verbosity_project_pa "test", cwd=high_verbosity_project_path, ) - assert result.capture == "Poe => echo Hello there!\n" + assert result.capture == "Poe => poe_test_echo Hello there!\n" assert result.stdout == "Hello there!\n" assert result.stderr == "" diff --git a/tests/test_poetry_plugin.py b/tests/test_poetry_plugin.py index 66fb32862..44465bb73 100644 --- a/tests/test_poetry_plugin.py +++ b/tests/test_poetry_plugin.py @@ -56,7 +56,7 @@ def test_task_accepts_any_args(run_poetry, projects, setup_poetry_project): cwd=projects["poetry_plugin"], ) assert result.stdout == ( - "Poe => echo --lol=:D --version --help\n--lol=:D --version --help\n" + "Poe => poe_test_echo --lol=:D --version --help\n--lol=:D --version --help\n" ) # assert result.stderr == "" @@ -83,7 +83,7 @@ def test_running_tasks_without_poe_command_prefix( cwd=projects["poetry_plugin/empty_prefix"].parent, ) assert result.stdout == ( - "Poe => echo --lol=:D --version --help\n--lol=:D --version --help\n" + "Poe => poe_test_echo --lol=:D --version --help\n--lol=:D --version --help\n" ) # assert result.stderr == "" diff --git a/tests/test_sequence_tasks.py b/tests/test_sequence_tasks.py index 94a8717d1..1292fa06c 100644 --- a/tests/test_sequence_tasks.py +++ b/tests/test_sequence_tasks.py @@ -46,7 +46,7 @@ def test_a_script_sequence_task_with_args(run_poe_subproc, esc_prefix): assert result.stderr == "" -def test_cmd_multiple_value_arg(run_poe_subproc): +def test_sequence_task_with_multiple_value_arg(run_poe_subproc): result = run_poe_subproc( "multiple-value-arg", "hey", "1", "2", "3", project="sequences" ) diff --git a/tests/test_shell_task.py b/tests/test_shell_task.py index 54921fe97..88e707f88 100644 --- a/tests/test_shell_task.py +++ b/tests/test_shell_task.py @@ -105,7 +105,7 @@ def test_global_interpreter_config(run_poe_subproc, projects): assert result.stderr == "" -def test_cmd_multiple_value_arg(run_poe_subproc): +def test_shell_task_with_multiple_value_arg(run_poe_subproc): result = run_poe_subproc( "multiple-value-arg", "hey", "1", "2", "3", project="shells" ) diff --git a/tests/test_task_running.py b/tests/test_task_running.py index 418aceb01..dae4297e0 100644 --- a/tests/test_task_running.py +++ b/tests/test_task_running.py @@ -3,7 +3,7 @@ def test_ref_task(run_poe_subproc, projects, esc_prefix): result = run_poe_subproc("also_echo", "foo", "!") assert ( result.capture - == f"Poe => echo POE_ROOT:{projects['example']} Password1, task_args: foo !\n" + == f"Poe => poe_test_echo POE_ROOT:{projects['example']} Password1, task_args: foo !\n" ) assert ( result.stdout == f"POE_ROOT:{projects['example']} Password1, task_args: foo !\n" From dba44579f01863095fc55f1eac71b22c3e28de0f Mon Sep 17 00:00:00 2001 From: Nat Noordanus Date: Sat, 11 Jun 2022 21:42:47 +0200 Subject: [PATCH 8/8] debug windows test --- tests/fixtures/graphs_project/pyproject.toml | 11 ++++++----- tests/test_cmd_tasks.py | 2 +- tests/test_graph_execution.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/fixtures/graphs_project/pyproject.toml b/tests/fixtures/graphs_project/pyproject.toml index 548d2e199..b975cd71a 100644 --- a/tests/fixtures/graphs_project/pyproject.toml +++ b/tests/fixtures/graphs_project/pyproject.toml @@ -3,17 +3,18 @@ greet = "echo hello" _noop.shell = ":" -_about = "echo about" -_do_setup = "echo here we go..." +_about = "echo about" +_do_setup = "echo here we go..." + [tool.poe.tasks.think] - shell = "echo Thinking $first_thing and $subject2" + cmd = "echo Thinking $first_thing and $subject2" deps = ["_noop", "_do_setup"] uses = { first_thing = "_about $subject1" } args = [{ name = "subject1", positional = true }, { name = "subject2", positional = true }] [tool.poe.tasks.deep-graph-with-args] - shell = "echo $greeting1 and $greeting2" + cmd = "echo $greeting1 and $greeting2" deps = ["_do_setup", "think $subject1 $subject2"] - uses = { "greeting1" = "greet $subject1", greeting2 = "greet $subject2"} + uses = { greeting1 = "greet $subject1", greeting2 = "greet $subject2"} args = ["subject1", "subject2"] diff --git a/tests/test_cmd_tasks.py b/tests/test_cmd_tasks.py index 3db087703..866ea1301 100644 --- a/tests/test_cmd_tasks.py +++ b/tests/test_cmd_tasks.py @@ -37,7 +37,7 @@ def test_cmd_task_with_multiple_value_arg(run_poe_subproc, is_windows): result = run_poe_subproc("multiple-value-arg", "hey", "1", "2", "3", project="cmds") if is_windows: assert result.capture == 'Poe => poe_test_echo "first: hey second: 1 2 3"\n' - assert result.stdout == '"first: hey second: 1 2 3\n"' + assert result.stdout == '"first: hey second: 1 2 3"\n' else: assert result.capture == "Poe => poe_test_echo first: hey second: 1 2 3\n" assert result.stdout == "first: hey second: 1 2 3\n" diff --git a/tests/test_graph_execution.py b/tests/test_graph_execution.py index 982ad8a2b..195c53d0c 100644 --- a/tests/test_graph_execution.py +++ b/tests/test_graph_execution.py @@ -5,8 +5,8 @@ def test_call_attr_func(run_poe_subproc): "Poe => :\n" "Poe <= echo about\n" "Poe <= echo hello\n" - "Poe => echo Thinking $first_thing and $subject2\n" - "Poe => echo $greeting1 and $greeting2\n" + "Poe => echo Thinking about and\n" + "Poe => echo hello and hello\n" ) assert result.stdout == ( "here we go...\n" "Thinking about and\n" "hello and hello\n"