Add minimal Python API and task runner (#5903) #9955
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
This introduces an ultra-minimal uv API and the concept of Tasks.
uv API
The intent of the uv API is to provide the ability to use uv programmatically from Python. It consists of a single function
uv()
that shells out a string to the uv binary. The goal here is to generally support every conceivable uv command, option, and argument without a maintenance burden.Tasks API
What is a task? I think that it can be better understood as a user-defined command. The intent of the Tasks API is to allow a user to conveniently run their tasks in the context of their uv-managed project. It consists of a decorator
@task
to mark functions as tasks and a functionrun_tasks
to autogenerate a CLI that can run their tasks.@task
The
@task
decorator registers task names and functions in a dictionary. It optionally takes dependencies as a string using the first positional arg orneeds
kwarg.The decorator can be written multiple ways:
@task
@task()
@task("...")
@task(needs="...")
The optional
needs
argument can help to ensure that task dependencies are available in the uv-managed project before the task is run. It supports the same range of arguments and options as theuv add
command. It can be used to add development dependencies, which most task dependencies probably should be, but the Tasks API does not make this assumption for the user.I considered additional support for unpacking the args tuple and
Sequence
types (likelist
andtuple
), but I felt that this provided too many ways to specify dependencies and those ways are visually noisier. I wanted using@task()
anduv()
to look and feel as natural as using the command line, and that can only be replicated with strings.run_tasks
The
run_tasks
function inspects and uses properties of the decorated task functions to generate a CLI that can execute the tasks as subcommands.Tasks are converted to CLI commands in the following fashion:
Test Plan
tasks.py
Roadmap
Task autodiscovery
On the roadmap could be the automatic discovery of user-created tasks to expose them as top-level uv commands.
Example task discovery
Currently the user is free to name and place their task module(s) however they'd like, but if autodiscovery is considered, a standardized name and place within the project structure might be beneficial for performance optimization. Configuration through environment variable or TOML is another option.
For security purposes, a user-defined task that shadows a uv command should:
What about tasks in
pyproject.toml
?Specifying tasks in
pyproject.toml
is not precluded with these changes, but careful thought should be given to such a feature. Various properties might be desired to do things such as to stopping or continuing tasks on first failure, displaying task help text or descriptions, or composing multiple tasks.Availability
These features are only available to users if
UV_PREVIEW
is set.