I'd rather `ruff` being merged with `ty` instead. `uv` for me is about package / project manager. It's not about code style. The only time `uv` should edit a code file is to update its dependencies (PEP 723).
On the other hand, both `ruff` and `ty` are about code style. They both edit the code, either to format or fix typing / lint issues. They are good candidates to be merged.
To clarify, `ruff` and `uv` aren't being merged. They remain separate tools. This is more about providing a simpler experience for users that don't want to think about their formatter as a separate tool.
The analogy would be to Cargo: `cargo fmt` just runs `rustfmt`, but you can also run `rustfmt` separately if you want.
Isn’t there `uv tool run ruff` already for this? Or `uv run ruff` if it’s a proper dependency? I’m not sure what’s the point of a special shortcut command, unless there are plans to make it flexible so it’ll be an abstraction over formatters (unifying ruff, black, etc).
Yeah, you can definitely use `uvx ruff` (an alias for `uv tool run ruff`) to invoke Ruff. That's what I've done in my own projects historically.
The goal here is to see if users like a more streamlined experience with an opinionated default, like you have in Rust or Go: install uv, use `uv init` to create a project, use `uv run` to run your code, `uv format` to format it, etc. Maybe they won't like it! TBD.
(Ruff is installed when you invoke `uv format`, rather than bundled with the uv binary, so if you never use `uv format`, there aren't any material downsides to the experiment.)
> (Ruff is installed when you invoke `uv format`, rather than bundled with the uv binary, so if you never use `uv format`, there aren't any material downsides to the experiment.)
That’s thoughtful design and could be worth mentioning in the blog post.
It's part of the mission for uv to become "cargo for python". A one stop swiss-army knife for everything you need to manage a Python project. I think it'll get a `uv test` command at some point too.
The whole point is you just install `uv` and stop thinking about the pantheon of tools.
It'll be interesting to see how the test is done. At the tox level, or the pytest level? (Or another level?) I can see all being useful and ergonomic, but tox's multi-environment setup might fit into it really well.
Is `uv format` supposed to be an alias for `ruff check`?
Stupidly I ran `uv format` without `--check` (no harm done and I can `git diff` it) so I didn't see the changes it made but `ruff check` does still show things that can be fixed with `ruff check --fix`. If I'm guessing correctly the difference is coming down to the fact that I have (in my submodule where all changes were made) a pyproject.toml file with ruff rules (there's also a .flake8 file. Repo is being converted). Either way, I find this a bit confusing userside. Not sure what to expect.
I think one thing I would like is that by default `uv format` spits out what files were changed like `uv format --check` does (s/Would reformat/Reformatted/g). Fine for the actual changes not to be displayed but I think this could help with error reduction. Running it again I can see it knows 68 files were changed. Where is that information being stored? It's pretty hard to grep out a number like that (`grep -R \<68\>`) and there's a lot of candidates (honestly there's nothing that looks like a good candidate).
Also, there's a `--quiet` flag, but the output is already pretty quiet. As far as I can tell the only difference is that quiet suppresses the warning (does `--quiet` also suppress errors?)
uv format
warning: `uv format` is experimental and may change without warning. Pass `--preview-features format` to disable this warning.
36 files reformatted, 31 files left unchanged
uv format --quiet
36 files reformatted, 31 files left unchanged
I like the result for `--quiet` but I have a strong preference that `uv format` match the verbosity of `uv format --check`. I can always throw information away but not recover. I have a strong bias that it is better to fail by displaying too much information than fail by displaying too little. The latter failure mode is more harmful as the former is much more easily addressed by existing tools. If you're taking votes, that's mine.
Anyways, looking forward to seeing how this matures. Loved everything so far!
Including a formatter in a package manager doesn't make sense to me. Seems like obvious feature creep.
My understanding was that uv is for installing dependencies (e.g. like pip) with the added benefit of also installing/managing python interpreters (which can be reasonably thought of as a dependency). This makes sense. Adding more stuff doesn't make sense.
I’m sure you’re a old man on the verge of death who loves yelling at clouds but enforcement and application of consistent code formatting has been considered a basic part of project management for a while now. Recent langage provide it as part of core project management tooling.
Given uv is openly strongly inspired by cargo and astral also has tooling for code formatting, the integration was never a question of “if”.
And I would think the next logical step here is to have a `uv lint` option here that runs ˋty` under the hood ?
I would love to see a world where there is a single or a set of standard commands that would prepare your python project (format, lint, test, publish). Maybe that’s the vision here?
this is very much in line with the unix philosophy - it delegates formatting to ruff and simply provides a unified front end that calls out to the right specialized tool. think of it as a makefile.
One can find repos using `make format` / `make lint`/ `make typecheck` / or similar
I remember David Beazley mentioning that code with Makefiles were relatively easier to analyze based on ~Terabyte of C++ code and no internet connection (pycon 2014)
https://youtube.com/watch?v=RZ4Sn-Y7AP8
That `make format` command was not defined by the Make developers, but by the team using Make in their project. They picked their favorite formatter and defined a shortcut. In this case, the uv developers are forcing the command on everyone, and they're using it to cross-promote their own formatting tool.
There is wisdom in knowing when -- and how -- to break standards. Don't know if this is the case, but I think it is. If introducing fmt powers to UV meant it had to consider tradeoffs elsewhere where it might hurt its quality somehow then maybe, but in this case UV is more like an umbrella, unifying the interface for pip, venv, builds... And now fmt. All keeping each separate domain isolated without details leaking to one another.
Abstraction. Not having to know all the innards (or even names) of each until you want to. It's all there if you want to, but stuff like uv (or cargo, or go's toolset) greatly simplifies 3 scenarios in particular: starting a new project, joining an existing project, and learning Python for the first time.
All 3 scenarios benefit from removing the choice of build tool, package manager, venv manager, formatter, linter, etc., and saying, "here, use this and get on with your life".
How is "uv format" a better name, or more "abstract", etc. etc., than "ruff check"? Why is it easier to think of my formatter and package manager (or whatever other pieces) as being conceptually the same tool, given that they are doing clearly different, independent and unrelated things?
And why is any of this relevant to first-time Python learners? (It's already a lot to ask that they have to understand version control at the same time that they're learning specific language syntax along with the general concept of a programming language....)
The spirit of the unix philosophy is not implementing MxN use cases separately. Running the same program as a separate binary or as a subcommand has nothing to do with it
The reality is, ecosystems evolve. First, we had mypy. Then more type checkers came out: pyre, pyright, etc. Then basedpyright. The era of rust arrived and now we have `ty` and `pyrefly` being worked on heavily.
On the linter side we saw flake8, black, and then ruff.
Decoupling makes adapting to evolution much easier. As long as both continue to offer LSP integrations it allows engineers to pick and chose what's best.
The whole premise of uv that you don't need to know that you can install specific python version using eg pyenv (`uv python install` or `uv run` may do it implicitly), you don't need to know about `python -m venv`/virtualenv (`uv venv`), or how to create lock files pip-tools / pipenv / poetry / etc(`uv lock`), or pipx (`uv tool install`) or `pip install`/ `pipenv install`/`poetry add` / many others (`uv add`), or how to build artifacts setuptools / hatchling / poetry way / etc (`uv build`). Other commands such as `uv sync` didn't break new ground too.
`uv format` is similar (you don't need to know about `ruff format` / black / yapf ).
All actions listed in your first paragraph, except for installing specific Python versions, are actions related to the area of packaging. Doing it in one tool is completely sensible. I'm not a fan of uv managing Pythons, but I guess that ship has sailed.
But formatting code is a completely new area that does not fit uv.
I enjoy using uv a lot but am getting afraid that it is getting bloated for no reason. For ex., the number of niche flags that a lot of subcommands support is very high + some of them seemingly achieve the same result(uv run --no-project and uv run --active). I'd rather them working on improving existing tools and documentation than adding new (redundant) functionality
It's really difficult to do Python projects in a sound, reproducible, reasonably portable way. uv sync is in general able to build you only a package set that it can promise to build again.
But it can't in general build torch-tensorrt or flash-attn because it has no way of knowing if Mercury was in retrograde when you ran pip. They are trying to thread a delicate an economically pivotal needle: the Python community prizes privatizing the profits and socializing the costs of "works on my box".
The cost of making the software deployable, secure, repeatable, reliable didn't go away! It just became someone else's problem at a later time in a different place with far fewer degrees of freedom.
Doing this in a way that satisfies serious operations people without alienating the "works on my box...sometimes" crowd is The Lord's Work.
> But it can't in general build torch-tensorrt or flash-attn because it has no way of knowing if Mercury was in retrograde when you ran pip.
This is a self-inflicted wound, since flash attention insist on building a native C++ extension which is completely unnecessary in this case.
What you can do is the following:
1) Compile your CUDA kernels offline.
2) Include those compiled kernels in a package you push to pypi.
3) Call into the kernels with pure Python, without going through a C++ extension.
I do this for the CUDA kernels I maintain and it works great.
Flash attention currently publishes 48 (!) different packages[1], for different combinations of pytorch and C++ ABI. With this approach it would have to only publish one, and it would work for every combination of Python and pytorch.
While shipping binary kernels may be a workaround for some users, it goes against what many people would consider "good etiquette" for various valid reasons, such as hackability, security, or providing free (as in liberty) software.
I don’t understand why adding a subcommand to uv is being considered bloat.
uv is already a complex tool, but it has excellent documentation. Adding a straightforward, self-explanatory subcommand like this doesn’t seem out of place.
This is obviously a great move. I don't know why so many commenters here are against making things better. "Can't you just do <this slightly worse thing> already?". Well yes. But it's slightly worse.
I don't think being one word longer ("uvx ruff format" vs "uv format") counts as being is worse.
I think it is much worse to create a special case that obscures the actual formatter being run and how it is being run (is ruff now preinstalled, or is it downloaded and cached in the same way as other tools?)
Not really. If you know about uv, you know how to use "uv tool run", so you know how to use any formatter of your choice (which you can find easily on Google, arguably easier than reading the documentation and learning about uv format).
I find this hard to believe since black doesn't even have the same rules as black's next version and I never changed version without something being reformatted.
Also because of fun, if you reformat again with the older version it won't go back to as it was before :)
This feels like feature creep. I've been using uv more and more over the past year (mostly because I work with projects that use it) and although I like it and recognize the advantages, it is still not my first choice, and this kind of thing isn't going to help that...
What's wrong with this approach specifically? Go does it this way. Rust does it this way. Elixir does it this way. It reduces the toil in setting up and using projects in those ecosystems substantially. It unifies community effort behind a common set of tools and provides beginners and experts alike with a shared entrypoint to projects.
What's wrong with the approach is that it goes against basic principles of the Python ecosystem. Python has always followed the policy of standardising mechanisms and allowing implementations to develop and peacefully coexist. The Python way fosters diversity of implementations. Note that uv itself would not be a reasonable project if not for Python's approach to diverse tooling.
You cite good examples where other languages have chosen to standardise tooling. We can discuss the pros and cons of that choice. But it is a choice, and Python already made a different choice.
One thing I wonder about is what happens in pyproject? Do you use tool.ruff/tool.ruff.format or tool.uv.format or what? Are people who only know "uv format" supposed to understand that part? Does ruff start honoring tool.uv.format? Which have priority over which in search. Does it behave differently when you run uv format vs ruff format? etc
Mixing a package manager, (which is needed for prod package installs) with dev-only tooling is analogous to an "attractive nuisance" (not that I'm saying anyone is a child mind). I know Go and Rust do it, but thinking from first principles, it sounds like a bad idea.
It really does sound like a bad idea, and now that I've used cargo a lot, I want a lot more of those bad ideas in my life.
Seriously, if uv becomes to Python what cargo is to Rust, the developer experience for Python is going to be vastly better than before. I've been writing Python professionally for more than 25 years, and getting paid to work around it's crummier parts, and I'm thrilled to be able to throw away all that knowledge and just use uv.
It wouldn't surprise me if the ruff featurset eventually gets integrated into uv and ty. The linting seems to better suited to ty which would be able to provide more intelligent linting since it understands the codebase better. And the formatting seems better suited to uv since that's all about managing your project.
go fmt, cargo fmt, deno fmt, dart format, etc. it's hardly a new trend to ship a formatter with an all-in-one package manager for a language. It's convenient for new projects to not have to set up an additional dependency.
I anticipate this will make it much easier for me to get my little team of actuaries formatting their code.
The impact of uv on our onboarding and utilisation of python has already been huge, and any way I can easily improve their code hygiene is a good one. Yes, I could get them to use ruff standalone, or set up pre-commit hooks etc for them, but the simple mental model that comes from `uv <do something>` is really beneficial.
Will have a play around with this and see how it goes. Would love to be able to hook into other formatters too, but not sure if that's easy or even possible already. For example, I would love it if `uv format` also formatted our SQL/dbt models.
At that point I think you start wanting Makefiles, or preferably IMO justfiles. Then you can run `just format` and have it format your combined Python/SQL/Bash/TypeScript project.
It's a minor issues in teams where people use inconsistent formatting. This causes needless complications when merging code and additional work related to resolving conflicts that shouldn't exist to begin with.
Some languages (Go, Rust) have essentially solved this issue to the point where blindly running the formatters these languages have solves the problem and is uncontroversial.
Sadly, the language of choice for me (Kotlin) has a big unaddressed problem here where what the IDE does for formatting and what independent formatting tools do are two things that are hard to align for mostly the historical reasons that what the IDE does is fragmented over different bits of code that don't listen to the same configuration. There is a lot of variation in preferences for indentation, where to put new lines, line length, what order to put imports in, which imports to use wildcards for (if any at all), etc. Particularly imports are a problem because the bit of code that organizes imports is separate from the bit of code that formats code in the IDE.
The common solution of using IDE plugins to work around this is a bit of a kludge. The proper solution would be a more sane way to just make the IDE externally configurable so that build tools can make the IDE do exactly the same as what they do without requiring users to manually configure their IDEs just right by installing plugins or fiddling with configuration. This stuff should not be user controllable if there is a build file that defines the proper formatting.
Coding agents actually add to this problem. Because getting those to stick to formatting conventions is tricky. Unless you have tools that just fix that properly.
So good change in uv and probably something I'd be using on my next python project (I do those once in a while).
That's exactly what I mean by kludge. And this attitude is exactly the problem and reason why most languages continue to do the wrong thing here.
Your solution requires user discipline and fiddling with things that should just work right without fiddling. And it needs to happen on every development environment. You can't really enforce it except via annoying additional kludges in the form of failing builds.
I've never been on a team where this was done right. I've been on plenty of teams with convoluted half enforced formatting rules (and thousands of violations).
I know how to fix it for my own code. But being able to force everyone I have to work with to do the same thing over and over again is the problem that needs solving. Everybody just shrugs it off and does nothing about it. What are you going to do. It's always been this miserable this way. Industry wide apathy on this topic.
That's why I appreciate what Google did with Go here so much. Not a fan of the language necessarily. But they did the right thing with making code formatting not optional and a compile error to skip.
Stuff like this should not be a debate or discussion or a follow this 20 step process to setup your work environment properly but just something that works right (for fuzzy definitions of right) as specified by the build file in the code repository.
It's a minor annoyance that I wish Jetbrains would just take more serious.
DevOps are the disciple that tames the developer team malpractices, it doesn't stop at formating, static analysis, misbehaved dependencies taken directly out of Internet without IT approval, no proper security workflows, there is no need for user disciple with manual steps.
This is starting to sound like uv is a trojan horse that was introduced as a package manager and is now seeking to replace the diverse python ecosystem with a totalizing approach that is anathema to the the python way (standardize protocols, accommodate diverse implementations).
Cargo is a hybrid of package manager and build system. So it has frontend fommands wrapping a formatter and loads of other stuff, like code linters, as part of the build system. I've used cargo to build projects even when they have no dependencies and I don't plan to bundle them up and publish them as crates.
Thanks for pointing that out. This is news to me. uv has been on my radar for a while and was considering switching to it as a better dependency manager. I didn't realise that it had ambitions beyond being "a better pip." At face value this is a real turn-off. Definitely violates the "do one thing and do it well" principle and puts it squarely in the "does complicated things that I want to avoid" (like poetry) category.
Ok, but we will go a step further and also integrate the remaining of ruff features? Because we have `go vet`. Does it even make sense to have the linter integrated too?
I am not sure I like this either. I think linter and formatter are more like developer dependencies, especially because both formatter and linters are generally things that you want to lock to a specific version to avoid e.g. CI failures or mass changes when a version is updated. But I can understand that having a formatter always available may be nice.
internally, they are working on ty and some of its logic is going to have to call out to uv. I imagine that things like this is being built to experiment with some of the connections and interfaces between tools.
The astral team is pretty responsive to questions and feedback. If this type of change concerns you (as an actual user of the tool) please reach out to them. My big thing right now is integrations with workspaces. And if special case commands is the answer,,, well not ideal but I’ll take it.
The native integration offers persistent configuration, caching, and project-aware behavior that uvx (which just creates an ephemeral venv) doesn't provide.
Having worked with many python repos, that didn’t know any better to follow conventions or that the tooling ecosystem has meaningful options, I am ecstatic to see formatting and linting be a first class feature of the modern python experience.
I know this is a hot take, but so much headache saved down the road to “force” this stuff up front.
Does it have to be "force" stuff up front? Surely there are less violent ways to ease new developers into conventions and tooling than the dictatorial approach.
uv is trying to deliver the same experience as cargo does for rust. Just install a single CLI and it's the only tool you have to worry about when working on your Python project.
There's nothing wrong with `ruff format`, but it's nice to have `uv` as a universal entrypoint.
> Try out uv format in your next project and see how it fits into your development workflow. The experimental nature means your feedback could help shape how this feature evolves.
So maybe nobody has been waiting for this and the feedback will be: we don’t need this.
Also it uses ruff under the hood. If it’s integrated with uv, an advantage is one less tool to juggle.
I've been playing around with go quite a bit lately, and now think that being bundled is actually a really serious advantage.
Being able to just to "go fmt", without needing any additional tools, is a really great thing about the language.
The only danger that I can see (and it is a big one) is that Python doesn't have the same kind of consistency that go does. It might end up failing just because so many people use Python in such different ways.
Yes, one advantage is that tools/editors will start to standardize on it. I quite enjoyed the seamless experience of go formatting as I started learning go. It felt like one less thing to worry about. Just worked.
I landed in python last year, the pre uv time for me. The language itself is fine, but the project organization sucked. What kind of folder structure to choose? Do I use pip, env, pipenv, poetry? How to format, and with which settings? I've read tens of blog post, all giving different choices, all equally reasonable, all having some downsides.
The great thing about uv is not that their choices are best, it's that the choices have been made, the gordian knots cut. There is a good enough standard to build upon. Future python projects will look a lot more like each other, and less time will be wasted on organizational minutiae.
Not all devs have very deep knowledge of the ecosystem, some will get to use a tool only if it's part of the default set of tools they're provided.
Plus, it saves on memorizing a name if you only use python once in a long while.
There just isn't much of a reason not to.
As someone who has worked on package managers quite a bit in the past, and for that examined prior art across package managers, that's because Cargo is doing things very well on almost all fronts. Partially because of their RFC process and partially because they have the luxury of being a "newer" package manager that doesn't have to live with ecosystem baggage going many decades back.
There are/were definitely some weaker spots with Cargo (e.g. private registry support was meh for some time), but if one were tasked to build a package manager and were only allowed to pick a single one to take inspration from, Cargo is definitely the way to go.
Of course we already have it automated in pre-commit checks, I'm just mildly annoyed that it's two different commands in the first place (though I'm sure there is some good historical reason). The distinction/ordering between them isn't really clear as a user, I just want "find and fix everything you can, error if you cant autofix" every time.
Just so you know, when people say "I hate this paper cut", they aren't really asking how they can put in extra work to get around it. Obviously hey can add some alias to ~/.bashrc... on every computer he uses. The complaint is that he has to do that in the first place. It's still annoying.
I prefer having things this way, because it respects the fact that I may have a different idea from the next person about how the pieces should be put together.
OK and the vast majority of people excluding you and them probably have a very close-or-nearly-identical idea about what should happen. So everyone can be happy, there's nothing being lost here.
Anyone from uv reading this?
please scrap this thing, there is a separate formatter ruff that anyone ll use if they want a formatter. please do not complicate stuff. ruff ll come with its own configuration. this will have its own config at some point. potential rule clashes, ignore plugins. please do not go in this direction
Cool. I want a do it all python tool. Ruff is great. Having it out of the box with uv is great. Less crap to mess with. I haven’t tried ty yet, but looking forward to not having to mess with pyright.
Meanwhile, they provide identical functionality. (`Under the hood, it calls Ruff’s formatter to automatically style your code according to consistent standards.`)
Good questions. I don't think we'd ever deprecate Ruff because `uv format` exists, and adding `uv format` won't have any impact on Ruff's release cycles or development. The analogy would be to Cargo: `cargo fmt` just runs `rustfmt`, but you can also run `rustfmt` separately if you want.
A lot of users just want a simpler experience. They want to install uv, run `uv run` to run their project, `uv format` to format it, etc. The idea here is to experiment with providing that functionality and see if folks find it useful. Maybe they won't want it! It's experimental :)
i expect to hear "hey replygirl, can we upgrade from ruff to uv format?" from 5 of my coworkers in the next month, and "what's the difference between ruff and uv format?" from another 10. per interaction i expect 2 minutes of reading and explaining, plus an average 5 minutes listening to the other party wax philosophical. so the convenience costs my job $400
I'm just going to ask this: if your coworkers ask "can we upgrade from ruff to uv format," and it takes you that much time to explain it, have you just considered going "sure thing," spending two hours on Twitter, and pushing a commit and getting paid for it?
now i've spent 2 minutes implementing, 1 minute drafting and assigning the pr, 10 minutes checking everything, 10 minutes each of two reviewers' time, 10 minutes of qa's time, and 1 minute reporting. it's also likely i spend 2 minutes explaining what it is to each of our PMs and our CTO and why they don't need to worry about it. then i still need to field questions from devs, this time "why did we change this?" and still "what's the difference?". so that costs the company even more.
Package managers providing a shortcut to call a standardized formatter is a very popular feature in many languages, also not hard to understand the appeal:
On the other hand, both `ruff` and `ty` are about code style. They both edit the code, either to format or fix typing / lint issues. They are good candidates to be merged.
The analogy would be to Cargo: `cargo fmt` just runs `rustfmt`, but you can also run `rustfmt` separately if you want.
The goal here is to see if users like a more streamlined experience with an opinionated default, like you have in Rust or Go: install uv, use `uv init` to create a project, use `uv run` to run your code, `uv format` to format it, etc. Maybe they won't like it! TBD.
(Ruff is installed when you invoke `uv format`, rather than bundled with the uv binary, so if you never use `uv format`, there aren't any material downsides to the experiment.)
That’s thoughtful design and could be worth mentioning in the blog post.
The whole point is you just install `uv` and stop thinking about the pantheon of tools.
Stupidly I ran `uv format` without `--check` (no harm done and I can `git diff` it) so I didn't see the changes it made but `ruff check` does still show things that can be fixed with `ruff check --fix`. If I'm guessing correctly the difference is coming down to the fact that I have (in my submodule where all changes were made) a pyproject.toml file with ruff rules (there's also a .flake8 file. Repo is being converted). Either way, I find this a bit confusing userside. Not sure what to expect.
I think one thing I would like is that by default `uv format` spits out what files were changed like `uv format --check` does (s/Would reformat/Reformatted/g). Fine for the actual changes not to be displayed but I think this could help with error reduction. Running it again I can see it knows 68 files were changed. Where is that information being stored? It's pretty hard to grep out a number like that (`grep -R \<68\>`) and there's a lot of candidates (honestly there's nothing that looks like a good candidate).
Also, there's a `--quiet` flag, but the output is already pretty quiet. As far as I can tell the only difference is that quiet suppresses the warning (does `--quiet` also suppress errors?)
I like the result for `--quiet` but I have a strong preference that `uv format` match the verbosity of `uv format --check`. I can always throw information away but not recover. I have a strong bias that it is better to fail by displaying too much information than fail by displaying too little. The latter failure mode is more harmful as the former is much more easily addressed by existing tools. If you're taking votes, that's mine.Anyways, looking forward to seeing how this matures. Loved everything so far!
To your analogy, it’d be like `cargo clippy`
uv is like cargo for python.
If you only need a fast type checker you can just use ty, if you just need a fast formatter and linter you can just use ruff.
Combining ruff and ty doesn't make sense if you think about like this.
My understanding was that uv is for installing dependencies (e.g. like pip) with the added benefit of also installing/managing python interpreters (which can be reasonably thought of as a dependency). This makes sense. Adding more stuff doesn't make sense.
Think npm / go / cargo, not apt/yum/pip.
Given uv is openly strongly inspired by cargo and astral also has tooling for code formatting, the integration was never a question of “if”.
Cargo cargo cult?
That's probably the vision, given all from astral.sh, but `ty` isn't ready yet.
I would love to see a world where there is a single or a set of standard commands that would prepare your python project (format, lint, test, publish). Maybe that’s the vision here?
I remember David Beazley mentioning that code with Makefiles were relatively easier to analyze based on ~Terabyte of C++ code and no internet connection (pycon 2014) https://youtube.com/watch?v=RZ4Sn-Y7AP8
You can use uv without ruff. You can use ruff without uv. You can invoke ruff yourself if that’s what you want. Or use any other formatter.
I don’t think I understand what your complaint is.
All 3 scenarios benefit from removing the choice of build tool, package manager, venv manager, formatter, linter, etc., and saying, "here, use this and get on with your life".
And why is any of this relevant to first-time Python learners? (It's already a lot to ask that they have to understand version control at the same time that they're learning specific language syntax along with the general concept of a programming language....)
But most importantly, apart from breaking away from "UNIX-philosophy tools", what do you lose in practical terms?
The reality is, ecosystems evolve. First, we had mypy. Then more type checkers came out: pyre, pyright, etc. Then basedpyright. The era of rust arrived and now we have `ty` and `pyrefly` being worked on heavily.
On the linter side we saw flake8, black, and then ruff.
Decoupling makes adapting to evolution much easier. As long as both continue to offer LSP integrations it allows engineers to pick and chose what's best.
`uv format` is similar (you don't need to know about `ruff format` / black / yapf ).
But formatting code is a completely new area that does not fit uv.
But it can't in general build torch-tensorrt or flash-attn because it has no way of knowing if Mercury was in retrograde when you ran pip. They are trying to thread a delicate an economically pivotal needle: the Python community prizes privatizing the profits and socializing the costs of "works on my box".
The cost of making the software deployable, secure, repeatable, reliable didn't go away! It just became someone else's problem at a later time in a different place with far fewer degrees of freedom.
Doing this in a way that satisfies serious operations people without alienating the "works on my box...sometimes" crowd is The Lord's Work.
This is a self-inflicted wound, since flash attention insist on building a native C++ extension which is completely unnecessary in this case.
What you can do is the following:
1) Compile your CUDA kernels offline. 2) Include those compiled kernels in a package you push to pypi. 3) Call into the kernels with pure Python, without going through a C++ extension.
I do this for the CUDA kernels I maintain and it works great.
Flash attention currently publishes 48 (!) different packages[1], for different combinations of pytorch and C++ ABI. With this approach it would have to only publish one, and it would work for every combination of Python and pytorch.
[1] - https://github.com/Dao-AILab/flash-attention/releases/tag/v2...
uv is already a complex tool, but it has excellent documentation. Adding a straightforward, self-explanatory subcommand like this doesn’t seem out of place.
I think it is much worse to create a special case that obscures the actual formatter being run and how it is being run (is ruff now preinstalled, or is it downloaded and cached in the same way as other tools?)
So when I moved several projects from black to ruff, there were no changes made to the code.
Also because of fun, if you reformat again with the older version it won't go back to as it was before :)
You cite good examples where other languages have chosen to standardise tooling. We can discuss the pros and cons of that choice. But it is a choice, and Python already made a different choice.
Seriously, if uv becomes to Python what cargo is to Rust, the developer experience for Python is going to be vastly better than before. I've been writing Python professionally for more than 25 years, and getting paid to work around it's crummier parts, and I'm thrilled to be able to throw away all that knowledge and just use uv.
This smacks of feature-creep and I won't be incorporating it into any pipelines for the foreseeable future.
The impact of uv on our onboarding and utilisation of python has already been huge, and any way I can easily improve their code hygiene is a good one. Yes, I could get them to use ruff standalone, or set up pre-commit hooks etc for them, but the simple mental model that comes from `uv <do something>` is really beneficial.
Will have a play around with this and see how it goes. Would love to be able to hook into other formatters too, but not sure if that's easy or even possible already. For example, I would love it if `uv format` also formatted our SQL/dbt models.
Even moreso in the LLM age of tooling and coding agents.
Some languages (Go, Rust) have essentially solved this issue to the point where blindly running the formatters these languages have solves the problem and is uncontroversial.
Sadly, the language of choice for me (Kotlin) has a big unaddressed problem here where what the IDE does for formatting and what independent formatting tools do are two things that are hard to align for mostly the historical reasons that what the IDE does is fragmented over different bits of code that don't listen to the same configuration. There is a lot of variation in preferences for indentation, where to put new lines, line length, what order to put imports in, which imports to use wildcards for (if any at all), etc. Particularly imports are a problem because the bit of code that organizes imports is separate from the bit of code that formats code in the IDE.
The common solution of using IDE plugins to work around this is a bit of a kludge. The proper solution would be a more sane way to just make the IDE externally configurable so that build tools can make the IDE do exactly the same as what they do without requiring users to manually configure their IDEs just right by installing plugins or fiddling with configuration. This stuff should not be user controllable if there is a build file that defines the proper formatting.
Coding agents actually add to this problem. Because getting those to stick to formatting conventions is tricky. Unless you have tools that just fix that properly.
So good change in uv and probably something I'd be using on my next python project (I do those once in a while).
All major IDEs allow to save the format configurations, which can be stored on the repo alongside the code as the team official's configuration.
Coding agents solve this problem in that eventually all programming languages will be as relevant as mastering Assembly is nowadays.
I already do stuff in low code/no code, that in the past I would be manually writing code to sort out those issues.
In the meantime, you can also ask them to format generated code in whatever way one feels like it.
Your solution requires user discipline and fiddling with things that should just work right without fiddling. And it needs to happen on every development environment. You can't really enforce it except via annoying additional kludges in the form of failing builds.
I've never been on a team where this was done right. I've been on plenty of teams with convoluted half enforced formatting rules (and thousands of violations).
I know how to fix it for my own code. But being able to force everyone I have to work with to do the same thing over and over again is the problem that needs solving. Everybody just shrugs it off and does nothing about it. What are you going to do. It's always been this miserable this way. Industry wide apathy on this topic.
That's why I appreciate what Google did with Go here so much. Not a fan of the language necessarily. But they did the right thing with making code formatting not optional and a compile error to skip. Stuff like this should not be a debate or discussion or a follow this 20 step process to setup your work environment properly but just something that works right (for fuzzy definitions of right) as specified by the build file in the code repository.
It's a minor annoyance that I wish Jetbrains would just take more serious.
I don't know much about go.
https://docs.astral.sh/uv/concepts/build-backend/
I am not sure I like this either. I think linter and formatter are more like developer dependencies, especially because both formatter and linters are generally things that you want to lock to a specific version to avoid e.g. CI failures or mass changes when a version is updated. But I can understand that having a formatter always available may be nice.
The astral team is pretty responsive to questions and feedback. If this type of change concerns you (as an actual user of the tool) please reach out to them. My big thing right now is integrations with workspaces. And if special case commands is the answer,,, well not ideal but I’ll take it.
I know this is a hot take, but so much headache saved down the road to “force” this stuff up front.
Have developers really been waiting for this? What's wrong with ruff format?
uv is trying to deliver the same experience as cargo does for rust. Just install a single CLI and it's the only tool you have to worry about when working on your Python project.
There's nothing wrong with `ruff format`, but it's nice to have `uv` as a universal entrypoint.
So maybe nobody has been waiting for this and the feedback will be: we don’t need this.
Also it uses ruff under the hood. If it’s integrated with uv, an advantage is one less tool to juggle.
Being able to just to "go fmt", without needing any additional tools, is a really great thing about the language.
The only danger that I can see (and it is a big one) is that Python doesn't have the same kind of consistency that go does. It might end up failing just because so many people use Python in such different ways.
The great thing about uv is not that their choices are best, it's that the choices have been made, the gordian knots cut. There is a good enough standard to build upon. Future python projects will look a lot more like each other, and less time will be wasted on organizational minutiae.
There are/were definitely some weaker spots with Cargo (e.g. private registry support was meh for some time), but if one were tasked to build a package manager and were only allowed to pick a single one to take inspration from, Cargo is definitely the way to go.
Wary of the vc funded aspect though…
ruff: Aww, you're sweet!
uv format: Hello, human resources?
Meanwhile, they provide identical functionality. (`Under the hood, it calls Ruff’s formatter to automatically style your code according to consistent standards.`)
Both tools are still evolving enough that I would not want their individual release cycles to impact each other.
A lot of users just want a simpler experience. They want to install uv, run `uv run` to run their project, `uv format` to format it, etc. The idea here is to experiment with providing that functionality and see if folks find it useful. Maybe they won't want it! It's experimental :)
- cargo fmt
- go fmt
- deno fmt
- dart format