astral-sh / uv

An extremely fast Python package and project manager, written in Rust.
https://docs.astral.sh/uv
Apache License 2.0
28.01k stars 805 forks source link

Using `uv run` as a task runner #5903

Open my1e5 opened 3 months ago

my1e5 commented 3 months ago

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.

stan-dot commented 2 weeks ago

there are one tools to rule them all broader than just for Python is the Task runner mentioned above by @sisp

A popular and powerful cross-platform task runner is Task, and it is also available as a Python package (merely shipping the compiled Go binary) to ease its installation in Python projects.

also solves the problem of combinatorial explosion when N tools are used, but even more powerfully, as beyond just Python ecosystem

harkabeeparolus commented 2 weeks ago

To Be, Or Not To Be

First, the uv team at Astral have already decided that they are going to add some kind of task runner:

@charliermarsh commented on Aug 9

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

...So I do not think it's very helpful for anyone if we discuss our opinions for or against endlessly. I think the more constructive thing to do would be to help with the design.

Target Audience

There is indeed a diverse ecosystem of tools for Python, since it's an old language that predates modern workflow tools for other languages, such as cargo, npm, dotnet, et al.

All of this will continue to exist whether uv has a basic task runner or not. Senior Python developers can continue to deploy fancy customized toolchains for their teams or CI/CD.

However, for new Pythonistas, either students, or developers coming from newer language ecosystems such as .NET, Rust, or Javascript, it would be very helpful to have the mythical "Cargo for Python" or "One tool to rule them all". Read e.g. Rye's Philosophy and Vision for building "the one tool" that the majority of Pythonistas would use most of the time because it's the easy, obvious default. It won't solve every problem and corner case, perhaps, but it will cover most needs for mostly everyone most of the time.

The Zen Of Python

There should be one-- and preferably only one --obvious way to do it.

Building "the one tool" or "Cargo for Python" would be the obvious way to develop in Python. Of course there will be a diverse ecosystem of specialized tools for every situation... But the should be one obvious way to start, lint, format, test, build, and publish a normal open source Python project.

I think uv should become "the one tool", and I think that requires the same basic task running capabilities that all the other modern Python workflow tools have.

zanieb commented 2 weeks ago

The open question for me is whether or not we should be building a general purpose task runner, i.e., designing some sort of DSL, or investing specifically in uv lint, uv format, and uv test. I see a general purpose task runner as sort of antithetical towards creating a consistent experience for these core workflows.

zanieb commented 2 weeks ago

(While I think @harkabeeparolus has a great point that moving the design forward is the best way to help move this issue forward, I do think discussion on the goals of and motivation for a task runner are reasonable as they will help inform the design)

zgana commented 2 weeks ago

I want to build on this point from @chrisrodrigue earlier in the thread. With Hatch, we can tie scripts to specific sets of dependencies, installed into separate environments. This can be much more general than lint, format, test. Two examples from my team's project template:

I'm not at all opposed to expressing these sorts of things with plain old shell scripts. What we're still missing in uv however (unless I am just out of date here) is a way to tie scripts to a specific dependency group or union of dependency groups.

appenz commented 2 weeks ago

One more vote that this should be implemented.

I think there would be a lot of value for being able to define a default target that allows me to start a package without knowing anything about it. Most Node packages can be started with "npm run" and I do not have to know the name of the package or the main javascript file. With package managers likely being the default way how novice users will run python packages in the future, I think ease-of-use matters.

inoa-jboliveira commented 1 week ago

Hi everyone, this discussion is veering off course. If you’re not interested in the task runner, please consider downvoting the issue and moving on. I’ve explored the workarounds, but unfortunately, each one falls short in some way. Let’s avoid introducing philosophical debates about open source maintenance and stay focused on resolving the issue at hand. Thanks!

dbohdan commented 1 week ago

I have suggestions conditional on uv implementing a task runner.

Poe the Poet sequences

I use Poe the Poet as my task runner with both Poetry and uv. Something I really like about Poe is how it handles sequence tasks. I haven't seen it in other Python task runners. You can have a failure in a sequence abort the sequence immediately, have no effect, or only change the exit code of poe later. This is very useful, e.g., for independent checks that can fail.

Here is how I use it in my website project. (The Lua is for Pandoc.)

[tool.poe.tasks.check]
sequence = ["format", "lint", "type", "format-lua", "lint-lua"]
help = "Format and run all static checks"
ignore_fail = "return_non_zero"

Starting with Poe

If uv implements a task runner, I would like it to have a similar feature to Poe's sequences. More broadly, my impression is that Poe has well-designed features absent in other Python task runners. Poe also seems to be the go-to task runner for Poetry users. Because of this, I think reimplementing Poe the Poet would be a good starting point for uv. The existing design of Poe could be refined as needed in the process, like how it happened with the Ruff formatter.