nat-n / poethepoet

A task runner that works well with poetry.
https://poethepoet.natn.io/
MIT License
1.4k stars 58 forks source link

Sequences can't handle arguments :( #37

Closed rjurney closed 2 years ago

rjurney commented 2 years ago

I've read the code and I can't find any way to make a sequence accept an argument. The code actually says to throw an exception if any extra arguments are given :(

I need to run the task setup-artifacts before I run the task poetry add. Since poetry add takes an argument I need to feed it to the last command in the list. This seems unsupported. I read the code and I get lost but this tells me SequenceTasks don't accept arguments: https://github.com/nat-n/poethepoet/blob/c5ac6cf3f9561f3891f620dc576e707cbcf441f0/poethepoet/task/sequence.py#L53-L72

My pyproject.toml reads:

[tool.poe.tasks]
setup-artifacts = "scripts/setup_artifacts.sh setup-poetry"
add = [{ref="setup-artifacts"}, { cmd = "poetry add" }]

I run poe add moto and I get:

poe add moto
Poe the Poet - A task runner that works well with poetry.
version 0.10.0

Error: Sequence task 'add' does not accept arguments

USAGE
  poe [-h] [-v | -q] [--root PATH] [--ansi | --no-ansi] task [task arguments]

GLOBAL OPTIONS
  -h, --help     Show this help page and exit
  --version      Print the version and exit
  -v, --verbose  More console spam
  -q, --quiet    Less console spam
  -d, --dry-run  Print the task contents but don't actaully run it
  --root PATH    Specify where to find the pyproject.toml
  --ansi         Force enable ANSI output
  --no-ansi      Force disable ANSI output

CONFIGURED TASKS
  setup-artifacts
  add

This makes me a sad panda :( What would I need to do to make poe take arguments to sequences? Maybe put an argument for them like args_to=2 to reference the command in the sequence?

nat-n commented 2 years ago

Hi @rjurney, thanks for the feedback!

Yes, I skipped on supporting arguments for sequences the first time round for lack of clarity on how it could work without inelegance. I have a couple of ideas though.

One way to achieve this would be to instead use the task graph feature discussed in #26, for which there is already an experimental implementation in pre-release. I say experimental because it's not really documented or well tested yet.

So with the pre-release version of poethepoet I think you could do something like the following:

[tool.poe.tasks]
setup-artifacts = "scripts/setup_artifacts.sh setup-poetry"
add = { cmd = "poetry add", "deps" = ["setup-artifacts"] }

This example defines a minimalist task graph, with add being the sink node, that requires setup-artifacts to be run first. Let me know if this already works for you?

The other way is something I thought of recently but haven't yet tried would to build upon the named arguments feature (also in pre-release) and make ref tasks support passing arguments (in the same way as "deps" or "uses" references do for task graphs), so it would look something like:

[tool.poe.tasks]
setup-artifacts = "scripts/setup_artifacts.sh setup-poetry"
_poetry_add = "poetry add"

  [tool.poe.tasks.add]
  sequence = ["setup-artifacts", "_poetry_add $target"]
  args = ["target"]

Which would then be invoked as poe add --target moto. Probably the task graph solution is better.

Haffi921 commented 2 years ago

I have a similar issue. For simplicity, let's say I'd like to chain-run isort and black both on a specific file or folder under a rule format.

What I can do already is a general task for the whole project, like this:

[tool.poe.tasks]
isort = "isort ."
black = "black ."
format = ["isort", "black"]

OR statically specify files or folders

[tool.poe.tasks]
format_this_specific_file_why_would_I_ever_do_this = [
    {cmd = "isort ./src/util/error.py"},
    {cmd = "black ./src/util/error.py"}
]

But I cannot dynamically give a file or folder for both task to run on, like this: poe format specific/file.py. I imagine in your proposal this would be the solution?

[tool.poe.tasks]
....

    [tool.poe.tasks.format]
    sequence = ["isort $target", "black $target"]
    args = ["target"]

Is there already a method I can use to get these desired results that I am missing?


I can also imagine another solution for simple cases. Something like this:

[tool.poe.tasks]
format = ["isort $1", "black $1"]

Where $N where N is a number from [1, 2, 3,... ] of order of arguments given. I don't know the specifics if this would clash with any other poe features. But if not, maybe these two solutions could be implemented. One for dead-simple cases and the other one for when you need a bit more control/explicitness.

nat-n commented 2 years ago

Hello @Haffi921, I previously looked into supporting positional arguments (see #17), but haven't found a satisfactory way to do it that generalises well across use cases. The key difficulty is that shells don't let you arbitrarily set envvars like $1. I'm open to suggestions on that.

The example you gave with args should work on the latest pre-release, though I understand how it could be less convenient.

Haffi921 commented 2 years ago

Hey @nat-n, thanks for the reply. That's a shame, it would be a really nice feature. However, I also feel as the args solution is still powerful, if a bit verbose. I'd love to lend a hand at some point.

Still I tried it and it doesn't seem to work. It literally says "Sequence task 'format' does not accept arguments :grin:

Here is my pyproject.toml:

[tool.poe.tasks]
test = "pytest ."
retest = "pytest . --lf"

[tool.poe.tasks.format]
sequence = ["isort $target", "black $target"]
args = ["target"]

Here's the output:

PS C:\...> poe format --target .
Poe the Poet - A task runner that works well with poetry.
version 0.11.0b5

Error: Sequence task 'format' does not accept arguments

USAGE
  poe [-h] [-v | -q] [--root PATH] [--ansi | --no-ansi] task [task arguments]

GLOBAL OPTIONS
  -h, --help     Show this help page and exit
  --version      Print the version and exit
  -v, --verbose  Increase command output (repeatable)
  -q, --quiet    Decrease command output (repeatable)
  -d, --dry-run  Print the task contents but don't actaully run it
  --root PATH    Specify where to find the pyproject.toml
  --ansi         Force enable ANSI output
  --no-ansi      Force disable ANSI output

CONFIGURED TASKS
  test
  retest
  format
    --target

Again tho, not a big issue. It's not like I need isort and black on specific files. It was just something I thought might be fun to try and see if works.

More so that I just wanted you to know it didn't work. And I definitely think it would be a nice feature!

nat-n commented 2 years ago

Still I tried it and it doesn't seem to work. It literally says "Sequence task 'format' does not accept arguments 😁

My bad! it's not there yet... 😣

I'm in the middle of refactoring some related code at the moment, I'll see if I can get to work while I'm at it.

Haffi921 commented 2 years ago

Ahh makes sense, yeah no worries

nat-n commented 2 years ago

@rjurney As of v0.11.0 (just released) you can now do something like:

[tool.poe.tasks]
setup-artifacts = "scripts/setup_artifacts.sh setup-poetry"

[tool.poe.tasks.add]
sequence = [{ref="setup-artifacts"}, { cmd = "poetry add $package" }]
args = [{ name = "package", positional = true }]

which could be invoked like:

poe add moto

I hope this works for you :)

@Haffi921 Your example should work now too

Haffi921 commented 2 years ago

@nat-n Great! Well done, this is a cool feature!