uv downloads overtake Poetry for Wagtail users(wagtail.org) |
uv downloads overtake Poetry for Wagtail users(wagtail.org) |
I was one of the last holdouts, preferring to keep 2.7 support if it wasn't too much hassle, but we have to move on at some point. Fifteen years is long enough support.
https://docs.astral.sh/uv/reference/policies/license/
There is not true vs untrue open source unless perhaps you intend copyleft, but that has nothing to do with whether or not there is corporate backing. Even GNU itself has had corporate backing for its compiler work and other utilities.
Kudos to the uv developers for creating such an amazing piece of software!
uv doesn't solve all this, but it's reduced the amount of ways things can go wrong by a lot. And it being fast means that the feedback-loop is much quicker.
uv felt a bit immature at the time, but sounds like it’s way better now. I really want to try it out... but Poetry just works, so I don’t really have an incentive to switch just yet. (Though I’ve switched from FlakeHeaven or something to Ruff and the difference was heaven and hell! Pun in’tended.)
uv init
uv sync
and you're done
I'd say if you do not run into the pitfalls of a large python codebase with hundreds of dependencies, you'll not get the bigger argument people are talking about.
I... what? Python is a beautiful way to evolve beyond the troglodyte world of sh for system scripts. You are seriously missing out by being so pertinently against it.
Python is going through package managers like JS goes through trends like classes-everywhere, hooks, signals etc
And what if there are no binaries yet for my architecture, will it compile them, including all the dependencies written in C?
Instead there is pixi, which is similar in concept to uv but for the conda-forge packaging ecosystem. Nix and guix are also language-agnostic package managers that can do the job.
I was heavily invested into virtualenv until I had to upgrade OS versions, which upgraded the Python versions and therefore broke the venvs.
I tried to solve this by using pyenv, but the need of recompiling Python on every patch wasn't something which I would accept, specially in regards to boards like Raspberry Pis.
Then I tried miniconda which I initially only liked because of the precompiled Python binaries, and ultimately ended up using pyenv-managed miniforge so that I could run multiple "instances" of miniforge and therefore upgrade miniforge gradually.
Pyenv also has a plugin which allows to set suffixes to environments, which allows me to have multiple miniforges of the same version in different locations, like miniforge-home and miniforge-media, where -home has all files in the home dir and -media has all files on a mounted nvme, which then is where I put projects with huge dependencies like CUDA inside, not cluttering home, which is contained in a VM image.
It works really great, Jupyter and vscode can use them as kernels/interpreters, and it is fully independent of the OS's Python, so that OS upgrades (22.04 -> 24.04) are no longer an issue.
But I'm reading about all these benefits of uv and wish I could use it, but somehow my setup seems to have tied my hands. I think I can't use uv in my projects.
Any recommendations?
Edit: Many of my projects share the same environment, this is absolutely normal for me. I only create a new environment if I know that it will be so complex that it might break things in existing environments.
I've got a couple quite big Django projects for which I've used venv for years, and not once have I had any significant issues with it. Speed at times could have been better and I would have liked to have a full dependency list lock file, but that never caused me issues.
The only thing that comes to mind is those random fails to build of C/C++ dependencies. Does uv address this? I've always seen people rave about other benefits.
If you use venv then you have extra steps because you have to explicitly create the venv, then explicitly install the deps there with pip. If your project is designed for a specific python version then developers have to manage that separately (usually pyenv these days).
For people building apps uv replaces venv, pip and pyenv, while being way faster at doing all three of those (you can completely rebuild the virtualenv and install the dependencies from scratch in under a second usually because uv is faster at creating a virtualenv than venv and is very quick at relinking the dependencies from a package cache).
I often use Python for quick one off scripts. With UV I can just do `uv init`, `uv add` to add dependencies, and `uv run` whatever script I am working on. I am up and running in under a minute. I also feel confident that the setup isn't going to randomly break in a few weeks.
With most other solutions I have tried in the Python ecosystem, it always seemed significantly more brittle. It felt more like a collection of hacks than anything else.
https://docs.astral.sh/uv/guides/scripts/#declaring-script-d...
That plus this: https://news.ycombinator.com/item?id=42855258
Makes it pretty seamless for one-off scripts.
The developer experience is top notch with excellent documentation and many common concerns already handled by Wagtail or Django. A significant amount of Wagtail-specific code is declarative, essentially describing data model, relationships, and UI fields. The parts that you don't need stay out of the way. It's also agnostic of the type of front-end you want, with full and automatic support for headless mode with JavaScript client, using traditional Django templates SSR, or using a dynamic approach like HTMX.
Kudos to the Wagtail team!
We recently switched to PDM in our company because it worked very well in our tests with different package/dependency managers. Now I am rethinking if we should switch to uv while PDM usage is still not very wide-spread in our company. But PDM works very well, so I am not sure whether to keep using it.
Doesn’t make pdm bad in itself but that means there’ll be fewer pdm users around to report bugs, potentially fewer contributors to it too, fewer resources, etc.
I've been working with pip for so long now that I barely notice it unless something goes very wrong.
Using uv is an easy sell to anyone who has worked with Python.
Great work Charlie and team.
I wonder what it would take to get poetry on par with uv for those who are already switching to it? Poetry is definitely very slow downloading multiple versions of packages to determine dependencies (not sure how uv works around this?). Does uv have a better dependency checker algorithm?
Dependency resolution is slow because it's computationally very expensive. Because uv is written in Rust the resolution is just much much faster. IIRC they actually reuse the same resolution package that Cargo (Rust's package manager) uses.
The dependency resolution computation is an interesting problem. I think poetry at some point switched to mypyc for compilation (although I can't find conclusive evidence for it now). From my experience, mypyc doesn't really improve performance much compared to say writing a c/c++ extension. Perhaps offloading dependency resolution in poetry to a native c library is a way to match uv.
Different laws of physics, to start with.
Poetry and uv have quite different philosophy. Poetry is incredibly opinionated in how you should do things, and trying to make poetry fit an existing project or combining poetry with other tools is quite likely to break. Uv on the hand is far more flexible and easier to make work with your current workflow. For me that was the main reason I gave up poetry, and in that aspect poetry will probably never be 'on par' with uv since these aren't technical differences, but differences of philosophy.
Ruff for me meant i could turn 4 pre-commit hooks (which you have to configure to be compatible with each other too) into just 1, and i no longer dread the "run Pylint and take a coffee break" moment.
I jumped ship to UV recently. Though i was skeptical at first i don't regret it. It makes dependency management less of a chore, and just something i can quickly do now. Switching from Poetry was easy for me too, only package i had issues with was pytorch, but that just required some different toml syntax.
UV does not solve all the hard problems.
Maybe switch to Pixi?
Last week, I started developing directly in PyTorch containers using just pip and Docker. With GPU forwarding on Windows no longer being such a hassle, I'm really enjoying the setup. Still, I can’t shake the feeling that I might be overlooking something critical.
I’d love to hear what the HN crowd thinks about this type of env.
https://docs.astral.sh/uv/guides/integration/pytorch/
If the platform (OS) solution works for you that's probably the easiest. It doesn't for me because I work on multiple Linux boxes with differing GPUs/CUDAs. So I've use the optional dependencies solution and it's mostly workable but with an annoyance that uv sync forgets the --extra that have been applied in the venv so that if you "uv add" something it will uninstall the installed torch and install the wrong one until I re-run uv sync with the correct --extra again. (uv add with --extra does something different) And honestly I appreciate not having hidden venv states but it is a bit grating.
There are some ways to setup machine/user specific overrides with machine and user uv.toml configuration files.
https://docs.astral.sh/uv/configuration/files/
That feels like it might help but I haven't figured out how to configure get that to help it pick/hint the correct torch flavor for each machine. Similar issues with paddlepaddle.
Honestly I just want an extras.lock at this point but that feels like too much of a hack for uv maintainers to support.
I have been pondering whether nesting uv projects might help so that I don't actually build venvs of the main code directly and the wrapper depends specifically on certain extras of the wrapped projects. But I haven't looked into this yet. I'll try that after giving up on uv.toml attempts.
I also use it in docker to build the container.
https://docs.astral.sh/uv/guides/integration/pytorch/#instal...
First impressions of uv are quite nice, but how does one change Python versions once you have a project up?
I installed 3.13 with `uv python install python3.13`
I see bunch of Python versions now with `uv python list` (uv even found my old Anaconda 3.9 install from way back)
But how would I switch to 3.13?
LLM hallucinates with `uv venv use 3.13` but that command does not work.
I see from https://docs.astral.sh/uv/concepts/projects/config/#python-v... that one can specify the version in pyproject.toml, but should not there be a command line to switch?
Took a huge chunk of complexity out of bootstrapping projects which I was otherwise handling myself.
It'd be nice if we could have a shim for `uv` that allows it to play nice with `asdf` (there is an `asdf-uv` but seems to be about installing different versions of `uv` when instead I want to install different versions of python _via_ uv).
But being written in Rust means I'm having to also finally get somewhat proficient in Rust. Can any Rust developers comment on the quality of the uv codebase? I find it surprisingly procedural in style, with stuff like hundreds of `if dry_run` type things scattered throughout the codebase, for example. Is this normal Rust style?
uv tool is also a great replacement for pipx.
I think it's the way to go for Python dependency management in 2025.
Had an issue running something on the latest Python version installed (3.13) but only needed to 'downgrade' to 3.11 to run that particular script. Just a simple:
`uv run --python 3.11 --with openai-whisper transcribe.py`
And no need to mess with anything else.
type checking
That is why for projects I resolve everything by hand, add all coarsely audited 3rd party libraries to ./lib/, and the main entry file then does this:
#!/usr/bin/env -S /bin/sh -c "_top_dir=\"\$(dirname \"\$(realpath -s \"\$0\")\")\"; cd \"\$_top_dir\"; exec \"\$_top_dir/python/install/bin/python3\" -W once::DeprecationWarning -X dev \"\$0\" \"\$@\""
import os
import sys
# Insert ./lib/ in front of search path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "lib"))
...
I like the excellent standalone CPython by indygreg, now under astral-sh's github organization. Unpack as is into ./python/ and done. Because Arch Linux would just roll forward to whatever version is latest, introducing new warnings every month or two and havoc on any new major version.
Project is fully portable, copy anywhere that has glibc, run.
Don't get me wrong, Rust is great and I use it too, but for very different purposes than (system) scripts.
uv is not written in python so it doesn't suffer from the bootstrap problem of having a python version installed to begin using it. Users (new and even experienced) get confused and annoyed when they try to use python tooling in the same venv as their application instead of using pipx.
People also get confused and annoyed if they use mac and run `brew upgrade` and find themselves with python 3.13 or just any version that is new (yes we can pin to python@3.11 or whatever) so pyenv is a good option.
So now you have pdm, pipx, and pyenv to manage all this stuff. With uv all this hassle goes away.
A new and immature interpreter is going to have other problems:
- Lack of compatibility with CPython - Not up to date with latest version features - Incompatibility with CPython extensions
RustPython is a cool project, but it's not reached the big time yet.
I've had it with version managers that only target a single language or tool, the cognitive load is too high if there's more than a couple of languages in the mix.
What would be really nice is an asdf-like single package manager with language-specific plugins. That would save me a bunch of headaches.
(1) As uv’s governance is driven by a for-profit company, I see incentives that will eventually compromise on its benefits.
(2) Python packaging has historically been very fragmented, and more recently there’s been lots of work on standardization. That work will be impacted when users massively shift to one package installer.
Neither of those things are clear negatives, but they’re worth being aware of.
Charlie Marsh (who founded Astral that develops uv) is very engaged in the standardisation process around Python packaging. The whole idea around uv is to be something that follows the standards as much as possible. uv has been much more aggressive about conforming than the other package managers.
It's not that uv is not an option for me, I made this move to miniforge before uv was on my radar because it wasn't popular, but I'm still at a point where I'm not sure if uv can do what I need.
- uv init new-py-env
- cd new-py-env
- uv add jupyter
- uv build
These are executed super fast. Not sure if this could help your situation but it is worth to be aware of these.
- uv can install python and a virtualenv for you. Any command you run with `uv run` from the root of a repo will be aware of its environment, you don't even need to activate a virtualenv anymore. This replaces {pyenv, pyenv-virtualenv, virtualenvwrapper,...}.
- uv follows the PEPs for project config (dependencies, optional dependencies, tool configs) in the pyproject.toml so in case uv dies, it's possible to migrate away for the features are defined in the PEPs. Which is not the case for say, poetry.
- uv has a lock file and it's possible to make deps platform specific (Windows, Linux, MacOS, etc). This is in compliance with a PEP but not supported by all tools.
- uv supports custom indexes for packages so you can prefer a certain index, for example your company package index or pytorch's own index (for ML work).
- very fast, makes local dev very seamless and is really helpful in CI/CD where you might just setup and tear down python envs a lot.
Also, the team is responsive on Github so it's easy to get help.
With how much the ecosystem is moving, I don't know whether the way we're doing it is unusual (Django and some other big projects still have a tox.ini), obsolete (I can't find how ux obsoletes this), or perfectly fine and I just can't find how to replace pip with ux for this use case.
The pain of creating a python environment that is durable across different deployments had me going for the nuclear option with full containerisation.
- uv tool replaces pipx etc.
- uv pip --tree replaces pipdeptree (including 'inverse' mode)
- ...
You don't need `pyenv`, `poetry` and `pipx` anymore, `uv` does all of that for you.
It's a much more complete tool than pip. If you've used poetry, or (in other languages) cargo, bundler, maven, then it's like that (and faster than poetry).
If you haven't, in addition to installing dependencies it will manage and lock their versions (no requirements.txt, and much more robust), look after the environment (no venv step), hold your hand creating projects, and probably other things.
Edit to add: the one thing it won't do is replace conda et al, nor is it intended to.
If you pip install something, you install it on the system python (the python binary located at sys.executable). This can break systems if the wrong combination of dependencies comes together. This is why you should never install things via pip for other people, unless you asked them first.
Now how else would you install them? There is a thing called virtual environments, which basically allows you to install pip dependencies in such way, they are only there within the context of the virtual environment. This is what you should do when you distribute python programs.
Now the problem is how do you ensure that this install to the virtual environment uses specific versions? What happens when one library depends on package A with version 1.0 and another library depends on a package with version 2.0? Now what happens if you deploy that to an old debian with an older python version.. Before uv I had to spend literal days to resolve such conflicts.
uv solves most of these problems in one unified place, is extremely performant, just works and when it does not, it tells you precisely why.
The td;rd is that is has a lot less modes of failure.
The real point of uv is to be more than pip, though. It can manage projects, so basically CLI commands to edit your `pyproject.toml`, update a lockfile, and your venv all in one go. Unlike earlier tools it implements a pretty natural workflow on top of existing standards where possible, but for some things there are no standards, the most obvious being lockfiles. Earlier tools used "requirements.txt" for this which was quite lacking. uv's lockfile is cross-platform, although, admittedly does produce noisier diffs than requirements.txt, which is a shame.
I intend to use system python there but previously poetry will simply crash the whole Pi while installing itself.
I think it's little recognized that there is a scaling limit for snapshots. If you have 20 people developing 20 projects and they are co-located in the same room with the server builds work 50-80% of the time and people think it's fine. If you're the one guy who is remote and has a slow connection, builds work 0% of the time. The problem is that at slightly different times you get slightly different snapshots that aren't compatible with each other -- it's a scaling problem because if you add enough developers and enough projects it will eventually get you.
I've worked at other places when the mvn clean was necessary every time; other developers thought this shouldn't be necessary and I was a doofus except I was able to make consistent progress like a ratchet on the project and get it done and they weren't.
Where I am now mvn is just fine, whenever it screws up there's a rational explanation and we're doing it wrong.
Node/NPM was a poster child of an ecosystem where projects break three times a week, due to having too many transitive dependencies that are being updated too often.
That said, I do wish uv had `uv activate`. I like just working in the virtualenv without having to `uv run` everything.
function __auto_fab --on-variable PWD
iterm2_print_user_vars
if [ -d "fabfile" ]
if [ -d "fabfile/.venv" ]
if not set -q done_fab
and not set -q VIRTUAL_ENV
echo -n "Starting fabfile venv... "
pushd fabfile > /dev/null
source .venv/bin/activate.fish --prompt="[fab]"
popd > /dev/null
set -g done_fab 1
echo -e "\r Fabfile venv activated "
end
else
echo "Run gofab to create the .venv"
end
end
end
I've since deleted the one to do a .venv in this directory, but I think it was roughly this... function __auto_venv --on-variable PWD
if [ -d ".venv" ]
if not set -q done_venv
echo -n "Starting venv... "
source .venv/bin/activate.fish --prompt="[venv]"
set -g done_venv 1
echo -e "\r Venv activated "
end
end
end
(just tested that and it seems to work - the --prompt actually gets overridden by the project name from uv's pyproject.toml now though so that's not really necessary, was useful at some point in the past)These live in ~/.config/fish/conf.d/events.fish
uv build
Building source distribution...
running egg_info
writing venv.egg-info/PKG-INFO
Successfully built dist/venv-0.1.0.tar.gz
Successfully built dist/venv-0.1.0-py3-none-any.whlIf you want to build shapely against your own version of GEOS, then you fall outside of what uv does. What it does in that case is download the all build tool(s) specified by shapely (setuptools and cython in this case) and then hands over control to that tool to handle the actual compiling and building of the library. It that case it is up to the creator of the library to make sure the build is correctly defined and up to you to make sure all the necessary compilers and header etc. are set up correctly.
[1]: https://github.com/spack/spack/blob/develop/var/spack/repos/... [2]: https://github.com/spack/spack/blob/develop/var/spack/repos/...
But conda-forge packages (just like PyPI packages, or anything that does install-time dependency resolution really) are untestable by design, so if you care for reliably tested packages you can take a look at nix or guix and install everything through that. The tradeoff with those is that they usually have less libraries available, and often only in one version (since every version has to be tested with every possible version of its dependencies, including transitive ones and the interpreter).
All of these tools have a concept similar to environments, so you can get the right version of GEOS for each of your projects.
Nix/guix sound interesting. But one of my systems is an nVidia Jetson system, where I'm tied to the system's libc version (because of CUDA libraries etc.) and so building things is a bit trickier.
On Alpine and Arch Linux? Exactly nothing.
On Debian/Ubuntu? maybe the convoluted packaging process, but that's on you for choosing those distributions.
Then I clicked a link and got to https://prefix.dev/ ...
> pixi is a fast software package manager built on top of the existing conda ecosystem. Spins up development environments quickly on Windows, macOS and Linux.
Oh, build on top of conda. I am so going to stay the hell as far away from that as possible!
You're literally on the Pixi website, and you know its name if you want to look for forums, feed it into Perplexity, etc.
https://docs.astral.sh/uv/pip/environments/
I think uv supports conda envs
You can also import existing Python versions into uv, for example on my Mac it has imported the Homebrew versions.
I don't think there's a definite answer yet.
I work in a place with 200 developers, and 99% of pip usage is in automated jobs that last an hour. Shaving a couple seconds off that will not provide any tangible benefit. However moving 200 people from a tool they know to one they don’t comes at a rather significant cost.
It could be more than that.
I switched from pip to uv today in a Dockerized project with 45 total dependencies (top level + sub-dependencies included).
pip takes 38 seconds and uv takes 3 seconds, both uncached. A 10x+ difference is massive and if uv happens to be better suited to run on multiple cores it could be even more because my machine is a quad core i5 3.20ghz from 10 years ago.
> I work in a place with 200 developers
In your case, if you have 200 developers spending an hour on builds that could in theory be reduced down to 5 minutes per build. That's 11,000 minutes or 183 hours of dev time saved per 1 build. I know you say it's automated but someone is almost always waiting for something right?
That's always one major thing I saw breaking old builds: old binaries stop being hosted, forcing you to rebuild them from old source, which no longer builds under current toolchains - making you either downgrade the toolchain that itself may be tricky to set up, or upgrade the library, which starts a cascade of dependency upgrades.
It's not like Node projects are distributed with their deps vendored; there's too much stuff in node_modules.
Yes it does, that's the whole point. You can still go and install the first version of express ever put on npm from 12 years ago. You can also install any of the 282 releases of it that have ever been put on npm since then. That's the whole point of a registry, it wouldn't be useful if things just disappeared at some random point in time.
The only packages that get removed are malware and such, and packages which the vendor themselves manually unpublish [0]. The latter has a bunch of rules to ensure packages that are actually used don't get removed, please see the link below.
Yes you can find edge cases with problems. Using this as an argument for "breaks 3 times per week" does not hold.
It should also respect any CFLAGS and LDFLAGS you set, but I haven't actually tested that with uv.
Depends what you mean by "fully": https://docs.astral.sh/uv/pip/compatibility/
There's a number of places pip and uv diverge:
* uv makes some design choices that aren't always strictly compatible with the spec
* uv correctly implements the spec and it turns out pip, or the underlying library, didn't (I have worked on fixing a couple of these on the pip side)
* uv doesn't support legacy features still in pip
* Tool specific features or exact output diverge
This is not a criticism, but I've seen some users get irate with uv because they were under the impression that it was making much stronger compatibility guarantees.
(Also note that outside the web/mobile space, projects that weren't updated in a year are still young, not old. "Old" is more like 5+ years.)
The two things are related. If your typical project has a dependency DAG of 1000+ projects, a bug or CVE fix somewhere will typically cause a cascade of potentially breaking updates to play out over multiple days, before everything stabilizes. This creates pressure for everyone to always stay on the bleeding edge; with a version churn like this, there's only so many old (in the calendar sense) package dists that people are willing to cache.
This used to be a common experience some years back. Like many others, I gave up on the ecosystem because of the extreme fragility of it. If it's not like that anymore, I'd love to be corrected.
It used to prior to npm 5 when lockfiles were introduced (yarn introduced lockfiles earlier).
The non-trivial exception being if some dependecy was downloading resources on the fly (maybe like a browser compat list) or calling system libraries (eg running shell commands)