Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using uv run as a task runner #5903

Open
my1e5 opened this issue Aug 8, 2024 · 134 comments
Open

Using uv run as a task runner #5903

my1e5 opened this issue Aug 8, 2024 · 134 comments
Labels
enhancement New feature or improvement to existing functionality

Comments

@my1e5
Copy link
Contributor

my1e5 commented Aug 8, 2024

For those of us migrating over from Rye, one of its nice features is the built-in task runner using rye run and [tool.rye.scripts]. For example:

[tool.rye.scripts]
hello = "echo Hello from Rye!"
$ rye run hello
Hello from Rye!

It could have some more features - here is a selection of feature requests from the community:

A lot of these requested features are things that other 3rd party tools currently offer. I thought it might be useful to highlight a few other tools here, in particular because they also integrate with the pyproject.toml ecosystem and can be used with uv today.

Perhaps these can serve as some inspiration for a future uv run task runner and also in the meantime offer a solution for people coming over from Rye looking for a way to run tasks.

@chrisrodrigue
Copy link

Relevant comment from another issue: #5632 (comment)

@chrisrodrigue
Copy link

PDM supports this: https://pdm-project.org/latest/usage/scripts/

@charliermarsh charliermarsh added enhancement New feature or improvement to existing functionality preview Experimental behavior labels Aug 9, 2024
@charliermarsh
Copy link
Member

Yeah we plan to support something like this! We haven't spent time on the design yet.

@nikhilweee
Copy link

The pyproject standard already supports [project.scripts], so uv may not need to use its own table.
https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#creating-executable-scripts

@charliermarsh
Copy link
Member

[project.scripts] is a little different -- that's used to expose specific Python functions as executable scripts, and we do support that already.

@chrisrodrigue
Copy link

Perhaps naming this section tool.uv.tasks or tool.uv.aliases could help disambiguate that.

@nikhilweee
Copy link

nikhilweee commented Aug 10, 2024

Or maybe [tool.uv.run] to be consistent with the command uv run. Or we could even think about [tool.uv.commands].
I'm not a big fan of [tool.uv.scripts] since it conflicts with [project.scripts] and I myself got confused before.

@cdwilson
Copy link

This is the main thing I missed coming from hatch: https://hatch.pypa.io/dev/config/environment/overview/#scripts

@chrisrodrigue
Copy link

chrisrodrigue commented Aug 23, 2024

+1 to @nikhilweee suggestions. I think “command” reflects the intent/concept.

Hatch has an “environment” concept and supports running commands namespaced to an environment like so

hatch run test:cov

where “test” is a user-defined environment (with a dependency group) and “cov” is a user-defined command for that environment.

[tool.hatch.envs.test]
dependencies = [
 "pytest",
 "pytest-cov",
 "pytest-mock",
 "freezegun",
]

[tool.hatch.envs.test.scripts]
cov = 'pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src'

[[tool.hatch.envs.test.matrix]]
python = ["3.8", "3.9", "3.10", "3.11", "3.12"]

I would be curious to hear the use cases of nesting dependency groups and commands into “environments” like this rather than defining them at the top-level (i.e. [tool.uv.commands]/[tool.uv.dev-dependencies]).

@pietroppeter
Copy link

since it has not been mentioned yet, adding as a possible inspiration for design of tasks also pixi: https://pixi.sh/latest/features/advanced_tasks/

@metaist
Copy link

metaist commented Aug 28, 2024

I happen to be writing a cross-project task runner that supports a bunch of formats (e.g. rye, pdm, package.json, Cargo.toml; even uv's workspace config).

For what it's worth, almost all python runners use tool.<name>.scripts for task config (presumably inspired by npm's package.json format), so it's somewhat of an easier upgrade path for people coming from other tools.

https://github.com/metaist/ds

@inoa-jboliveira
Copy link

Also related to this thread, I wish uvx was uv run instead of uv tool run when inside a project.

uv tool run seems like something you would do to play with a tool, like ruff. But then you will eventually uv add ruff --dev and forever keep writing uv run ruff check instead of uvx ruff check which won't respect the locked version and will be in different virtualenv. It also means the tool could be running on a different Python (does not apply to ruff, but any other python lib) and all sorts of weird stuff can happen.

I know uv run stuff is still short, but it could be 4 keystrokes shorter.

Regarding uv run being a task runner it means people will type it waaaaay more often than uv tool run.
I would appreciate a dedicated command like uvr

@zanieb
Copy link
Member

zanieb commented Sep 8, 2024

@inoa-jboliveira I opened a dedicated issue for that #7186

@nikhilweee
Copy link

Putting together some thoughts about semantics. This issue is about adding support for running arbitrary instructions specified in pyproject.toml. I deliberately use the term instruction to avoid using any of the other terms under consideration (command, tool, script, etc).

What do we call these instructions?

Lots of existing tools refer to them as "scripts".

  1. npm and yarn have first class support for scripts. Users can define them in package.json
  2. composer also uses the same term. Users can define them in composer.json
  3. pdm takes inspiration from npm and also uses the term scripts. Users can define them in [tool.pdm.scripts]
  4. rye follows suit. Custom scripts are defined in [tool.rye.scripts]
  5. hatch also uses the term scripts, although they are tied to environments. Defined in [tool.hatch.envs.<env>.scripts]

It seems advantageous to just go with the term "scripts" because it is the de-facto standard. As noted by another user #5903 (comment), this would also reduce friction for users coming to uv from other package managers. That said, this approach has a major flaw because it overlaps with the concept of entry points defined in [project.scripts]. Entry points expose certain python functions as executable scripts, but do not allow arbitrary commands. Furthermore, [project.scripts] has already been established in PEP-0621, as the official spec. So what about other terms?

Another option is to use the term "tasks"

  1. pixi uses the term "tasks". Users can define them in the [tasks] table in pixi.toml
  2. bundler uses rake tasks. Although it resembles entry points, sh is supported.
  3. grunt and gulp also use the term "tasks". Although they are task runners, not package managers.
  4. gradle uses the term "tasks", defined in build.gradle

Another option is to call them "executables". dart uses this term in pubspec.yaml

We could also use "commands", although I wasn't able to find existing tools which use this term.

After settling on a name, an obvious thing to do is to let users define instructions in the [tool.uv.<name>] table.

How do we invoke these instructions?

There are two options here.

  1. Overload existing uv run <instruction> (follows from npm run <script>)
  2. Add a new subcommand uv invoke / uv command / uv task

How should these instructions be specified?

PDM's documentation around user scripts is pretty evolved, with support for a bunch of features.

  1. cmd mode, shell mode, composite mode
  2. Specify env vars and env files for each script
  3. Specify working dir and site packages for each script
  4. Specify order of arguments
  5. Specify pre and post scripts
  6. call a function from a python script (entry point)

Rye has its own format, which is a subset of PDM features.

  1. Specify env vars and env files for each script
  2. chain multiple scripts one after the other
  3. call a function from a python script (entry point)

I hope this serves as a starter for discussing additional details for this feature.

@charliermarsh
Copy link
Member

(Nice comment, thank you!)

@Xdynix
Copy link

Xdynix commented Sep 10, 2024

One nice thing about PDM is that if a command is not recognized as a built-in, it is treated as pdm run. Thus, pdm foobar would be shorthand for pdm run foobar, which executes the command defined in [tool.pdm.scripts.foobar].

@gdamjan
Copy link

gdamjan commented Sep 10, 2024

IMHO, pdm has the most extensive support for these scripts and I would personally like to see the same support in uv too. And if so, best to support the same pyproject section too 😱. It's especially nice when one doesn't have to use any other tools like Makefiles (ugh).

Alas, one can argue that the pdm support for scripts is feature-creep for uv, in which case the rye model works too :)

@patrick91
Copy link

Furthermore, [project.scripts] has already been established in PEP-0621, as the official spec. So what about other terms?

I wonder if would be a good time to maybe standardise this? I don't know if a pep is required, but since we have some many package managers for python it would be nice if we can have one way to define these instructions

@rmorshea
Copy link

rmorshea commented Jan 2, 2025

A plugin system for task runners

I'm curious to know what the folks here think about the alternative described in #10211. In short, the idea is that UV would supply a plugin system for task runners so that projects could use whichever task runner best suited their needs (e.g. just, doit, poethepoet, taskipy, or invoke just to name a few).

A quick example

From the user's perspective, usage of this plugin system wouldn't look significantly different from what's been discussed already. So, for example, you'd still be able to run your tests with a command like:

uv task test

A configuration of the plugin system which used Poe the Poet might then look something like:

[dependency-groups]
dev = ["poethepoet"]

[tool.uv.task]
command = "poe"

[tool.poe.tasks]
test = "pytest"

Given this, uv task test would essentially be an alias for:

uv run poe

There are probably some additional configuration options you'd need in order to deal with edge cases I haven't thought of, but hopefully this gets the basic idea across.

Why prefer a plugin system

  1. The UV devs wouldn't need to develop and maintain their own task runner system. One which would receive frequent pressure to grow in scope and complexity.

  2. A UV-based task runner, whatever form it might take, is unlikely to be as capable as tools like Just which are solely dedicated to that purpose.

  3. Because a UV-based task runner is likely to be relatively simple just to keep maintenance costs down, some projects will need to use other tools to manage their tasks anyway. As a workaround, a couple comments have suggested that you might alias usages of those tools within your UV tasks to keep UV as a central entry point for contributors:

    [tool.uv.tasks]
    lint = "uvx --from=rust-just just lint"
    fmt = "uvx --from=rust-just just fmt"
    test = "uvx --from=rust-just just test"

    In a case like this you end up having to sync two lists of tasks - one in UV and another in your tool of choice. This seems burdensome to maintain. By comparison, with a task runner plugin system you'd configure UV once with something like:

    [tool.uv.task]
    command = "uvx --from=rust-just just"

@lucabello
Copy link

@rmorshea I'm not a big fan of the "plugin" approach, mainly because it's easily included in the "alias" approach.

About (1), I think there is a general agreement on this issue, but the "alias" approach is not implementing a full-fledged task runner either (i.e., there's no dependency groups) it's just uv run aliases so that everyone can run the same test or lint without installing extra packages. It stil allows power-users to use a separate task runner without needing a separate installation.

About (2) and (3), I think the "alias" approach doesn't require you to maintain two lists of tasks if you don't want to. To exclusively rely on poe, you don't need to replicate the task list at all; you could simply have:

[tool.uv.task]
poe = "poe"  # poe = "uvx poe" is equivalent

[tool.poe.tasks]
test = "pytest"

You can then run uv task poe test and you're essentially using poe. The only difference with the "plugin" approach (which is a bit more complex imho) is running uv task poe test instead of uv task test. I believe the "alias" approach is also more transparent (other than simpler to implement), as it's always executing uv run behind the scenes, and that makes it easier - in my mind at least - to reason about when using simple aliases.

All the task runners you listed are executable via uv run, so this applies to all of them. Here's another example for just (assuming your actual tasks live in a justfile):

[tool.uv.task]
just = "uvx --from=rust-just just"

You can run uv task just if you wish, so uv task just test, uv task just lint, etc.


Albeit the "alias" approach is very simple (which is what most people seem to want and need), it allows for all of these power-usage scenarios and essentially includes the "plugin" approach, which is why I personally like the "alias" approach better :)

@tobiasdiez
Copy link

In the "alias-approach", how does one specify that a given command has certain external dependencies that should be installed before running it?

@axel-kah
Copy link

axel-kah commented Jan 2, 2025

In the "alias-approach", how does one specify that a given command has certain external dependencies that should be installed before running it?

In the end you are "aliasing" uvx invocations and uvx features the --with option to specify arbitrary dependencies.

@rmorshea
Copy link

rmorshea commented Jan 2, 2025

Maybe I'd need to read the rest of this thread to understand why this isn't the case, but the "alias" approach doesn't seem to provide any benefit over using uv run - from a user's perspective you'd be executing uv task just test instead of uv run just test. If that's true, maybe projects that are interested in using a 3rd party task runner like Just should just keep using uv run or contend with maintaining two task lists.

@tobiasdiez
Copy link

In the "alias-approach", how does one specify that a given command has certain external dependencies that should be installed before running it?

In the end you are "aliasing" uvx invocations and uvx features the --with option to specify arbitrary dependencies.

But that get's quite involved, doesn't it? You need to remember which dependencies you need for which task, kind of defeating the purpose of having predefined tasks in the first place.

Alternatively, you would need to define

[tool.uv.tasks]
lint = "uvx --with ruff ruff check"
test = "uvx --with pytest pytest"

@ksamuel
Copy link

ksamuel commented Jan 2, 2025

Not to mention arg proxying is necessary to allow those aliases to be flexible.

@lucabello
Copy link

@rmorshea IMHO the benefits of the "alias approach" over simply uv run become more apparent when the commands are not as simple as pytest.

What if you want to use a specific tool version / always pass some flags / etc? New users would need to read docs on what to uv run instead of simply executing uv task.

What if:

  • you want the project to always be tested with pytest --tb=short -vv - new users won't know this
  • you want a "test-network" command that only runs tests marked as "network" (pytest -vv -m network)
  • you want to use tooling the user hasn't necessarily installed, like doit or just
  • you want a specific version of a tool

Sure, you technically could document it somewhere and tell everyone: "to run the tests, execute uv run --from=rust-just just test" (or pytest -vv --tb=auto -m production, or whatever), but it's a lot easier to run uv task test and absorb the command complexity into the alias.


@tobiasdiez I think you'd use --with in the task definition, just as you wrote - note you don't need to specify it for the tool you're using, you can simply uvx ruff check. But if your task required an extra package to be present, that's yet another argument in favour of aliases - the user doesn't have to remember that, as the would just execute uv task test or whatever.

@rmorshea
Copy link

rmorshea commented Jan 4, 2025

Couldn't I just include rust-just in my dev dependency group so that I don't have to use a verbose command like that? That's why I had imagined the comparison would be between uv task just test and uv run just test.

@rmorshea
Copy link

rmorshea commented Jan 6, 2025

Now that I think about it, if UV shipped with a uvr alias for uv run. You could effectively get the exact same experience being described here if you installed taskipy in your dev dependency group:

uvr task test
[dependency-groups]
dev = ["taskipy"]

[tool.taskipy.tasks]
test = "pytest -vv"

Given that, as mentioned above, uv task scripts are "not implementing a full-fledged task runner" and are "just uv run aliases", perhaps providing a uvr alias and some easily discoverable documentation describing this pattern would satisfy people?

@ceejatec
Copy link

ceejatec commented Jan 6, 2025

@rmorshea I might be an oddball, but I'd personally prefer not to add another uvr binary. IMHO one of the best things about uv is its single-binary nature. In most environments I don't even install uvx. In your example, that wouldn't matter; I could just run uv run task test (and in fact I think I'm going to start doing exactly that - thanks for the pointer!). However, if it became commonplace for people to define tasks or scripts that invoked uvr directly, then those would break when uvr wasn't available.

uvx is kind of understandable as it isolates a whole sub-subcommand that is pretty separable from the rest of the uv experience (although as I said, I still kinda don't like it). uvr feels like a bridge too far though. It's only saving you three keystrokes and not really simplifying anything - uv run is still just as overloaded as it always was.

@rmorshea
Copy link

rmorshea commented Jan 6, 2025

That makes sense. Users can always define uvr as an alias (I already do on my machine). The section documenting this sort of pattern could explicitly suggest doing so for those whoe find uv run to be too repetitive.

dangotbanned added a commit to vega/altair that referenced this issue Jan 7, 2025
- Allows `uv run tools/tasks.py test` to be replaced with `uv run task test`
- Handles subprocess better for `pytest` and `sphinx-build`

Suggested in astral-sh/uv#5903 (comment)
@ksamuel
Copy link

ksamuel commented Jan 8, 2025 via email

@rmorshea
Copy link

rmorshea commented Jan 8, 2025

The alias really only saves you three characters which is really just a marginal benefit. Additionally, as mentioned above, UV could explain how to define an alias thus addressing the users who don't know how already.

@lucabello
Copy link

Just so it's not lost in the noise, the comment detailing the approach almost everyone seems to be agreeing on is here.

I'd love to hear some thoughts from the uv maintainers on this!

@mmerickel
Copy link

mmerickel commented Jan 8, 2025

I think the [tool.uv.tasks] and uv task strategy is great because it also doesn't clobber the default $PATH in the uv run subshell. So you can invoke uv task foo from uv task bar but you have to explicitly call uv task foo instead of just foo. I think this is a good thing. For example:

[tool.uv.tasks]
foo = "uv task lint"
lint = "ruff check"

Another issue I haven't seen brought up much would be how to invoke tasks defined by other projects in the workspace. You'd need something like uv task --package subpackage lint similar to --package on other commands. This difference in lookup is a great justification for not auto-injecting the tasks into the default $PATH used by uv run.

As far as what you can do / supported syntax in in the task definition - that is more controversial. Whether it's some variant of bash, parseable by shlex, or what, because you do need some mechanism to access env vars and chain multiple commands together and in a cross-platform way. This is super common in npm/yarn where you'll do things like:

{
  "scripts": {
    "build:prod": "NODE_ENV=production yarn run build",
    "publish:prod": "...",
    "build-and-publish:prod": "yarn run build:prod && yarn run publish:prod"
  }
}

Some dialect has to be decided for tool.uv.tasks that can handle cross-platform scenarios.

Don't forget at the very least you will always have an escape-hatch that you can just shell to a cross-platform python script that you write that can do the right thing on each platform, despite everyone saying how much they hate writing python scripts for a python tool :-)

[tool.uv.tasks]
foo = "python3 scripts/foo.py"

Finally, it'd be nice if there were a way for a task to say it depends on a dependency-group so that if it is invoked then that dependency group is automatically installed into the env.

Imagine:

[[tool.uv.tasks]]
name = "foo"
dependency-groups = ["foo-deps"]
command = "python3 scripts/foo.py"

[[tool.uv.tasks]]
name = "..."

or a dict-form which allows you to keep the simple structure of just a string on some commands:

[tool.uv.tasks]
lint = "ruff check"
bar = {
  command = "tox -e build"
}

[tool.uv.tasks.foo]
dependency-groups = ["foo-deps"]
command = "python3 scripts/foo.py"

@rmorshea
Copy link

rmorshea commented Jan 8, 2025

@lucabello, if it's true that in your proposal uv task scripts are "not implementing a full-fledged task runner" and are "just uv run aliases" then it's not clear why it's necessary to implement this feature if you can get a nearly identical user experience with:

[dependency-groups]
dev = ["taskipy"]

[tool.taskipy.tasks]
test = "pytest -vv"

As far as I can tell, the only difference is that you have to type a few more characters:

uv run task test  # currently supported via taskipy
uv task test      # your proposal

It seems to me that, at least until the ongoing standards discussions have been resolved, the taskipy trick is probably acceptable for most use cases.

@lucabello
Copy link

@rmorshea I think that given the scope we're setting, if uv wants to be the one tool to manage a Python project, having an internal solution is better than relying on a third-party package (that happens to be named task): what if it's discontinued, has a bug, etc? I'm not a uv maintainer, but I believe the scope of this issue has been made small enough that implementing it from scratch seems the way to go (to me at least).

The internals are also slightly different: taskipy is running custom shell commands, while uv task would be executing uv run behind the scenes; there has been concern in the previous comments about portability of using/writing shell commands.

I agree that the UX is very similar, and I think it's more of a maintenance/reliability/provenance type of problem for me; taskipy is good to use, surely, just like other task runners. But I'd argue uv has the chance to have their own task runner (this uv task thing) that also supports all other pip-installable task runners. The implementation is simple, small, and covers most uses cases - all if you use it in conjunction with another task runner (e.g. uv task just, and so on). uv isn't relying on an external task runner, but a user can choose to do so.

@zanieb
Copy link
Member

zanieb commented Jan 9, 2025

I'm working on scheduling design and implementation of this feature on the uv roadmap.

@birdhackor
Copy link

Is there an opportunity to integrate a feature similar to PDM that reads env files based on different CMDs? (PDM documentation is attached below)

https://pdm-project.org/en/latest/usage/scripts/#env_file
https://pdm-project.org/en/latest/usage/scripts/#shared-options

Currently, I use the environment variable UV_ENV_FILE=.env to automatically read the .env file. However, this feature has a drawback: if there is no .env file, it throws an error. I often encounter this issue when running uv run ... for the first time on a new project, and then I manually run touch .env to avoid the error.

Having behavior similar to PDM would be much more convenient.

@lucabello
Copy link

Just one small addition, after giving the uv task alias approach some thought; I think the missing puzzle piece would be the ability to specify a default command when you run uv task.

Whatever the syntax in pyproject.toml is, being able to alias the base uv task command to something allows to fully integrate uv with an external task runner by having it list the available commands.

Some examples:

# Poe the Poet
$ uv task  # aliased to `poe`
[...]  # more output
Configured tasks:
  lint
  test

# Just
$ uv task  # aliased to `just` with a default list recipe, or to `just --list`
Available recipes:
    lint
    test

# pydoit
$ uv task  # aliased to `doit list`
lint   Lint things.
test   Test things.

A possible way to configure this in pyproject.toml would be the way just does it, which is using the default name to specify the default behavior:

[tool.uv.tasks]
default = "uvx --from=rust-just just"
lint = "uvx --from=rust-just just lint"
test = "uvx --from=rust-just test"

In this example, uv task and uv task default would be equivalent.


This little addition would make the uv task integration with an external task runner completely transparent. Obviously, an alternative solution would be to define a separate alias (e.g., uv task just) and use that to run the commands, but then we're adding one extra words to all commands (which is fine, but maybe not as clean as it could be).

We'd go from:

uv task just  # shows the list of commands
uv task just lint  # executes `uvx --from=rust-just just lint`
uv task just test  # executes `uvx --from=rust-just just test`

to:

uv task  # shows the list of commands
uv task lint  # executes `uvx --from=rust-just just lint`
uv task test  # executes `uvx --from=rust-just just test`

Sorry for the extra noise!

@gesslerpd
Copy link

@zanieb Great that design for this is being scheduled!

Possibly some of this will come for free since [tool.uv.*] declarations are supported inside inline script metadata but it'd be great if script-based tasks were supported/considered as part of this.

For example, as of 0.5.17 release this is one method of running pytest against a single script with all of it's dependencies (including pytest) defined inline.

uv export --script test_example.py | uv run --with-requirements - pytest <options> test_example.py

@tringenbach
Copy link

Hi,

I am much more familiar with the NodeJs/Typescript/Webpack world than I am Python at this point in time.

The discussion I see in this Issue looks really encouraging.

I got excited and typed up my own thoughts, but that probably wasn't needed.

What do Python devs expect?

First I wanted to ask, what do Python developers expect? That seems really important, and it's not a question I can answer. How do popular projects solve this problem today? How do devs using Python for their day job expect this to work, and what are they doing today?

My own use cases

I saw someone mention shell aliases. Those don't really solve my use cases.

  • I'm on a team, and I need a bunch other people to all run the same commands
    • Some on Mac, some on Windows, different shells, different IDEs
    • Everyone works on other stuff too
  • I want the commands to be discoverable
  • I want to reuse some of these commands with CI/CD

NodeJs stuff

Back to my own thoughts from my NodeJs background.

In package.json, these kinds of tasks are defined using the "scripts" section. This automatically makes things confusing since Python has already standardized that word as meaning executables (which package.json defines under the bin key). Not much you can do about that, besides explain it in the documentation, but please do explain it.

"script" is overloaded

Script seems especially overloaded. Looks like at least hatch and PDM have something called scripts that are like these tasks. Python has "scripts" vs "modules" and so "uv run" talks about running "scripts", and the docs has a section on standalone "scripts" vs "projects", and also a section on "project.scripts".

PDM (which I'm not familiar with, just reading the docs) has a warning block in its documentation about this overloading of the word "scripts": https://pdm-project.org/latest/usage/scripts/#user-scripts It calls them "User Scripts". Looks like it also does the yarn shortcut thing.

npm / yarn / gulp / the word "run"

npm and yarn both use the run command with these tasks. Yarn even lets you admit the word run if the task name doesn't conflict with a yarn subcommand.

For a while the task runner "gulp" was popular, and it did use the word "task", so the word "task" is decent choice. I do worry about having too many words that mean the same thing in plain english to someone new to Python. (task, tool, run, script).

In the nodejs / npm ecosystem, there's a popular package called cross-env to solve the problem of setting environment variables in a way that works cross platform. It would be great if a solution to that problem was built in to uv's task runner.

It's not all that popular, but I've seen a couple of projects (such as Lit) using wireit, which I thought was neat in its minimalism, while still allowing tasks to depend on one another.

Another task running and workspace manager I've used in the nodejs world is nx. It's more about managing monorepos. Like uv, you end up prefixing everything with nx.

IDEs

IDE's usually want to display a list of tasks. If they are being defined in a straight forward way in pyproject.toml, that seems easy enough. But it might still be helpful to include a command to list tasks, or list tasks and their dependencies as a tree.

(I don't work on any IDE, so I don't know what their needs really are, but hopefully that use case is considered.)

Other features

Some other things that might be nice:

  • task dependencies
    • running one task first runs some others
  • nested tasks
    • colons are popular in tasks names, either for workspaces, or for steps or variants
  • hidden tasks
    • useful for a shared dependency / an internal task you want to call from other tasks, but don't want the shell to autocomplete
  • user defined task descriptions / help text

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improvement to existing functionality
Projects
None yet
Development

No branches or pull requests