-
Notifications
You must be signed in to change notification settings - Fork 998
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
Comments
Relevant comment from another issue: #5632 (comment) |
PDM supports this: https://pdm-project.org/latest/usage/scripts/ |
Yeah we plan to support something like this! We haven't spent time on the design yet. |
The pyproject standard already supports |
|
Perhaps naming this section |
Or maybe |
This is the main thing I missed coming from hatch: https://hatch.pypa.io/dev/config/environment/overview/#scripts |
+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
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. |
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/ |
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 |
Also related to this thread, I wish uvx was
I know Regarding |
@inoa-jboliveira I opened a dedicated issue for that #7186 |
Putting together some thoughts about semantics. This issue is about adding support for running arbitrary instructions specified in What do we call these instructions?Lots of existing tools refer to them as "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 Another option is to use the term "tasks"
Another option is to call them "executables". 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 How do we invoke these instructions?There are two options here.
How should these instructions be specified?PDM's documentation around user scripts is pretty evolved, with support for a bunch of features.
Rye has its own format, which is a subset of PDM features.
I hope this serves as a starter for discussing additional details for this feature. |
(Nice comment, thank you!) |
One nice thing about PDM is that if a command is not recognized as a built-in, it is treated as |
IMHO, Alas, one can argue that the |
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 |
A plugin system for task runnersI'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 exampleFrom 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 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
|
@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 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 [tool.uv.task]
poe = "poe" # poe = "uvx poe" is equivalent
[tool.poe.tasks]
test = "pytest" You can then run All the task runners you listed are executable via [tool.uv.task]
just = "uvx --from=rust-just just" You can run 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 :) |
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 |
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 |
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" |
Not to mention arg proxying is necessary to allow those aliases to be flexible. |
@rmorshea IMHO the benefits of the "alias approach" over simply 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 What if:
Sure, you technically could document it somewhere and tell everyone: "to run the tests, execute @tobiasdiez I think you'd use |
Couldn't I just include |
Now that I think about it, if UV shipped with a uvr task test [dependency-groups]
dev = ["taskipy"]
[tool.taskipy.tasks]
test = "pytest -vv" Given that, as mentioned above, |
@rmorshea I might be an oddball, but I'd personally prefer not to add another
|
That makes sense. Users can always define |
- 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)
Most windows user don't know how to define aliases, and you have to
define them in at least two shells. Sometimes it's not even possible
with some company policies.
Le lundi 6 janvier 2025 à 23:50, Ryan Morshead
***@***.***> a écrit :
… 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 if you find uv run to be too
repetitive.
—
Reply to this email directly, view it on GitHub
[#5903 (comment)],
or unsubscribe
[https://github.com/notifications/unsubscribe-auth/AABWFPW7COUSO7KZXFMXD4T2JMCCLAVCNFSM6AAAAABMGHOKM6VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDKNZUGA3DENJQGY].
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
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. |
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! |
I think the [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 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 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" |
@lucabello, if it's true that in your proposal [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 |
@rmorshea I think that given the scope we're setting, if The internals are also slightly different: I agree that the UX is very similar, and I think it's more of a maintenance/reliability/provenance type of problem for me; |
I'm working on scheduling design and implementation of this feature on the uv roadmap. |
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 Currently, I use the environment variable Having behavior similar to PDM would be much more convenient. |
Just one small addition, after giving the Whatever the syntax in 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 [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, This little addition would make the 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! |
@zanieb Great that design for this is being scheduled! Possibly some of this will come for free since For example, as of 0.5.17 release this is one method of running
|
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 casesI saw someone mention shell aliases. Those don't really solve my use cases.
NodeJs stuffBack to my own thoughts from my NodeJs background. In "script" is overloadedScript 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 " 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"
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 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 IDEsIDE's usually want to display a list of tasks. If they are being defined in a straight forward way in (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 featuresSome other things that might be nice:
|
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:It could have some more features - here is a selection of feature requests from the community:
tool.rye.scripts
rye#930A 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.Poe the Poet
https://github.com/nat-n/poethepoet
taskipy
https://github.com/taskipy/taskipy
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.The text was updated successfully, but these errors were encountered: