Open nat-n opened 4 years ago
use case:
[tool.poe.tasks.test]
help = "Run unit tests with coverage"
cmd = "pytest --cov-report=html"
[tool.poe.tasks.cov]
help = "Open HTML test coverage report"
shell = "start htmlcov/index.html"
Ideally, I'd want the cov
task to conditionally run the test
task first if index.html doesn't exist.
Hi this is definitely something that I have been looking for. Imagine you need to install some thing or run tests after install for your local dev but not in prod. If we use poetry than we can run only poetry install and be done with it. 🥹
[tool.poe.poetry hooks]
post_install = "post-install"
[tool.poe.tasks.post-install]
Sequence = [
{She'll="apt install something"},
{She'll="Poe test", condition="${dev}" },
]
Args=[{name=dev, default=True, type=bool}]
Here's what I have in mind for this feature so far. Comments welcome.
There are two distinct mechanisms for making a task conditional.
The check
option specifies another task (defaults to the expr task type with assert = true) which is executed first. If it returns non-zero then the main task execution is skipped.
[tool.poe.tasks.install-deps]
cmd = "apt install something"
check = "${ENV} != 'prod'"
The other mechanism is similar to how dependencies work in gnu make, by building on top of the existing deps mechanism. a task can declare a target
option that points to a file. If a task has a target declared then it will only execute if either that file does not exist, or it has as a dependency on a task with a target file that is newer that its own.
For example here package will run build, but build will only execute if there's no build artefact. So package will always execute if build does, or if build has otherwise executed more recently than it has (judging from the last updated dates of their respective target files).
[tool.poe.tasks.clean]
cmd = "rm -rf build"
[tool.poe.tasks.build]
cmd = "apt install something"
target = "build/app"
[tool.poe.tasks.package]
cmd = "..."
target = "app.zip"
deps = ["build"]
So then one way to interpret the scenario from @howeaj would be to make cov depend on test, and configure test with another new option called watch
, which specifies files equivalent to a target on a dependency but without having to have another task to depend on.
[tool.poe.tasks.test]
help = "Run unit tests with coverage"
cmd = "pytest --cov-report=html"
watch = ["src/**/*.py", "tests/**/*.py"]
target = "index.html"
deps = ["_src_changed"]
[tool.poe.tasks.cov]
help = "Open HTML test coverage report"
shell = "start htmlcov/index.html"
deps = ["test"]
Although I'm not sure this is really what you'd want?
I'm open to suggestions for a more elegant or powerful approach to this problem.
The goal of this project is to be the obvious choice of task runner for python projects, with the simplicity of npm scripts for simple use cases, but also with powerful features comparable to make (at least as far any python project is likely to need).
One key feature of make is being able to skip build targets that already exist.
I need to analyse this problem a bit more but so far I’m thinking an appropriate comparable feature would be for all tasks to support a
condition
option, which can either represent a relative path to a file or directory (with globbing?), the existence of which would make the condition false, or it could reference a python function to evaluate.Open questions:
what mechanisms should be available for overriding a condition? Is if enough to have a global
--force
CLI flag?how should this work for composite tasks? should it be possible to skip the condition for a single subtask? Or is all or nothing good enough?
If conditions can be defined in multiple ways then this could work similarly to tasks, which a generally defined as dictionaries which can be differentiated between different types, or as just a string which is interpreted as a default type. What should the default type be? (I'm thinking python function) Is there a better way of representing this?