Live data from Hacker News

A year of uv: pros, cons, and should you migrate

bitecode.dev

381–390 of 401 posts

Re: A year of uv: pros, cons, and should you migrate

#381

> You don't even need to know there is a venv, or what activation means. > All those commands update the lock file automatically and transparently.... It's all taken care of. When is the python community going to realize that simple is the opposite of easy? I don't see how hiding these aspects is desirable at all; I want to know how my programming tools work! With all due respect to the author, I don't like the assum…

A recurring theme I've seen in Python packaging community discussion is that a lot of people really seem to hate venvs, mostly for reasons I consider quite irrational. And if they don't outright hate the things, they fear having to try to explain them to newbies.

Keep in mind: there are huge numbers of people out there who will cargo-cult about how applying the sudo hammer to Pip fixed something or other (generally, because the root user has different environment variables). People even resent having to do user-level installations; they resent venvs even more. When the Python team collaborated with multiple Linux distros to add a system to protect against global user-level installs (because they were still interfering with system Python tools), a lot of people reacted by doing whatever they could to circumvent that protection, and advising each other on how to do so - thus the education effort described in https://discuss.python.org/t/the-most-popular-advice-on-the-... . People really would, apparently, rather add `--break-system-packages` to a command line so that they can keep installing everything in the same place, than attempt to understand even the basics of environment management. And we're talking about programmers here, mind.

And then there are the complaints about how the __pypackages__ proposal (https://peps.python.org/pep-0582/) failed - e.g. https://chriswarrick.com/blog/2023/01/15/how-to-improve-pyth... . There were serious issues with that idea, which only became clear as the discussion dragged on and on across literally years (https://discuss.python.org/t/pep-582-python-local-packages-d...). But people were quite upset about having to stick with the old venv model - including the guy who wrote the best explanation of venvs I know, which I frequently refer beginners to (https://chriswarrick.com/blog/2018/09/04/python-virtual-envi...).

A lot of programmers seem to love having the details not only hidden, but as inaccessible as possible, as long as the UI is nice enough. (Unless we're talking about their own code. Then, hundred-line functions are just hunky-dory.)

Re: A year of uv: pros, cons, and should you migrate

#382

The challenge I have with adopting uv is it feels like it doesn't have a great replacement for poetry's `[tool.poetry.scripts]` block. For instance, from a personal project that uses a src layout, without being a package, I have this in my pyproject.toml: [tool.poetry] ... packages = [{ include = "*", from = "src", format = "sdist" }] ... [tool.poetry.scripts] botch = "launcher:run_bot('botch')" beat = "launcher:run_…

[project.scripts] is the PEP621 equivalent, supported by multiple backends including vanilla Setuptools. (When you use [tool.poetry.scripts], it's really the build backend, Masonry, that cares.) So that's the uv way, too. Or the "bear skins and stone knives" way.

I don't know what you mean by "without being a package". I guess you mean that Poetry will also run your code without installing it anywhere, and use the marked entry points directly. Per the other replies, apparently uv will get an equivalent soon. But really, the point of having `pyproject.toml` in the first place is to explain how to build an installable wheel and/or sdist for your project, and you basically get it for free. (Even if you don't include a [build-system] table, the standards say to use Setuptools by default anyway.)

(Of course, uv can already `run` your entry point, but this involves installing the code in a temporary venv.)

> without some pretty major refactoring of my internal structure and import declarations. Maybe I've accidentally cornered myself in a terrible and ill-advised structure?

Possibly. Is the code up on GitHub? I could take a look.

Re: A year of uv: pros, cons, and should you migrate

#383
post #22

I think the biggest praise I can give uv is that as a non Python dev, it makes Python a lot more accessible. The ecosystem can be really confusing to approach as an outsider. There’s like 5 different ways to create virtual environments. With uv, you don’t have to care about any of that. The venv and your Python install are just handled for you by ‘uv run’, which is magic.

https://xkcd.com/927/

Re: A year of uv: pros, cons, and should you migrate

#384

Earlier quoted context omitted.

Then why even have the dependency file? If the dependency file is wrong, and describes versions that are incompatible with the project, it should be fixed. Duplicating that information elsewhere is wrong. Lockfiles have a very obvious use case: Replicable builds across machines in CI. You want to ensure that all the builds in the farm are testing the same thing across multiple runs, and that new behaviors aren't intr…

>Then why even have the dependency file? Horses for courses. Dependency files - whether the project's requirements (or optional requirements, or in the future, other arbitrary dependency groups) in `pyproject.toml`, or a list in a `requirements.txt` file (the filename here is actually arbitrary) don't describe versions at all, in general. Their purpose is to describe what's needed to support the current code: its dir…

> Lockfiles are meant to describe the exact version of everything that should be in the environment to have exact reproducible behaviour (not just "working"), including transitive dependencies.

It is wrong to specify the versions for your transitive dependencies except to achieve reproducible builds, as in CI or other situations. If a dependency fails to correctly describe their requirements in their pyproject.toml it is a bug and should be fixed in the relevant upstream.

> There are others who'd like to replicate their builds: application developers who don't want to risk getting bug reports for problems that turn out to be caused by upstream updates.

If your application only works with specific versions of dependencies and has bugs in others, that should be described in pyproject.toml.

> In principle, if you need a lockfile, you aren't distributing a library package anyway.

It's irrelevant what kind of project you're describing, library, application, build-tooling, etc. Your pyproject.toml should contain the correct information for that project to run. If your project cannot run, contains bugs, or otherwise needs more specific information than is present in the pyproject.toml the answer is to fix the pyproject.toml.

Reproducible builds for the purpose of testing or producing hash-identical wheels, or similar situations where the goal is producing an exact snapshot of a build, is the only reason to be using lockfiles. None of those use cases aligns with, for example, tracking the lockfile in source control.

Re: A year of uv: pros, cons, and should you migrate

#385

I really like uv and I have successfully got rid of miniconda but : - I wish there was a global virtual environment which could be referenced and activated from terminal. Not every new scripts needs their own .venv in their respective folder. uv takes the route of being project centered and based on file system, this works for me most of the time but sometime it doesn't. - I wish we could avoid the .python_version fi…

Agreed, I like to have a "general use" environment to use for various one-off interactive python sessions, scripts or jupyter notebooks.

Re: A year of uv: pros, cons, and should you migrate

#386

The challenge I have with adopting uv is it feels like it doesn't have a great replacement for poetry's `[tool.poetry.scripts]` block. For instance, from a personal project that uses a src layout, without being a package, I have this in my pyproject.toml: [tool.poetry] ... packages = [{ include = "*", from = "src", format = "sdist" }] ... [tool.poetry.scripts] botch = "launcher:run_bot('botch')" beat = "launcher:run_…

[project.scripts] is the PEP621 equivalent, supported by multiple backends including vanilla Setuptools. (When you use [tool.poetry.scripts], it's really the build backend, Masonry, that cares.) So that's the uv way, too. Or the "bear skins and stone knives" way. I don't know what you mean by "without being a package". I guess you mean that Poetry will also run your code without installing it anywhere, and use the ma…

Yes, the code is at https://github.com/tiltowait/botch

I'm planning on asking on the Astral Discord server once I have some time to set aside to it.

By "without it being a package", I mean that I don't have `src/foo`, which has `src/foo/__main__.py`, but e.g. `src/main.py`.

Re: A year of uv: pros, cons, and should you migrate

#387
post #220

Earlier quoted context omitted.

What do you do when you accidentally run pip install -r requirements.txt with the wrong .venv activated? If your answer is "delete the venv and recreate it", what do you do when your code now has a bunch of errors it didn't have before? If your answer is "ignore it", what do you do when you try to run the project on a new system and find half the imports are missing? None of these problems are insurmountable of cours…

>What do you do when you accidentally run pip install -r requirements.txt with the wrong .venv activated? As someone with a similar approach (not using requirements.txt, but using all the basic tools and not using any kind of workflow tool or sophisticated package manager), I don't understand the question. I just have a workflow where this isn't feasible. Why would the wrong venv be activated? I activate a venv accor…

> Why would the wrong venv be activated?

Because when you activate a venv in a given terminal window it stays active until you deliberately deactivate it, and one terminal and one venv looks much like another.

> I activate a venv according to the project I'm currently working on.

So just manual discipline? It works (most of the time), but in my experience there's a "discipline budget"; every little niggle you have to worry about manually saps your ability to think about the actual business problem.

> "what do you do when you 'accidentally' manually copy another project's pyproject.toml over the current one and then try to update?" I'm pretty sure they won't be able to protect you from that.

Copying pyproject.toml is a lot less routine than changing directories in a terminal window. But if I did that I'd just git checkout/revert to the original version.

> the code simply wouldn't have those errors. Because that venv has its own up-to-date listing of requirements; so when I recreated the venv, it would naturally just contain what it needs to.

So how do you ensure that? pip dependency resolution is nondeterministic, dependency versions aren't locked by default and even if you lock the versions of your immediate dependencies, the versions of your transitive dependencies are still unlocked.

> If the listing were somehow out of date, I would have to fix that anyway, and this would be a prompt to do so.

Flagging up outdated dependencies can be helpful, but getting forced to update while you're in the middle of working on a feature (or maybe even working on a different project) is rather less so. Especially since you don't know what you're updating - the old versions were in the venv you just clobbered and then deleted, so you don't know which dependency is causing the error and you've got no way to bisect versions to find out when a change happened.

> Do tools like Poetry and uv scan my source code and somehow figure out what dependencies (and versions) I need? If not, I'm not any further behind here.

uv has deterministic dependency resolution with a lock file that, crucially, it uses by default without you needing to do anything. So if you wiped out your cache or something (or even switched to a new computer) you get the same dependency versions you had before. There's no venv to clobber in the first place because you're not activating environments and installing dependencies - when you "uv run myproject" the dependencies you listed in pyproject.toml, there's no intermediate non-version-controlled thing to get out of sync and cause confusion. (I mean, maybe there is a virtualenv somewhere, but if so it's transparent to me as a user)

> I spent this morning exploring ways to install Pip 0.2 in a Python 2.7 virtual environment, "cleanly" (i.e. without directly editing/moving/copying stuff) starting from scratch with system Python 3.12. (It can't be done directly, for a variety of reasons; the simplest approach is to let a specific version of `virtualenv` make the environment with an "up-to-date" 20.3.4 Pip bootstrap, and then have that Pip downgrade itself.)

Putting pip inside Python was dumb and is another pitfall uv avoids/fixes.

Re: A year of uv: pros, cons, and should you migrate

#388

Earlier quoted context omitted.

[project.scripts] is the PEP621 equivalent, supported by multiple backends including vanilla Setuptools. (When you use [tool.poetry.scripts], it's really the build backend, Masonry, that cares.) So that's the uv way, too. Or the "bear skins and stone knives" way. I don't know what you mean by "without being a package". I guess you mean that Poetry will also run your code without installing it anywhere, and use the ma…

Yes, the code is at https://github.com/tiltowait/botch I'm planning on asking on the Astral Discord server once I have some time to set aside to it. By "without it being a package", I mean that I don't have `src/foo`, which has `src/foo/__main__.py`, but e.g. `src/main.py`.

>By "without it being a package", I mean that I don't have `src/foo`, which has `src/foo/__main__.py`, but e.g. `src/main.py`.

This doesn't matter. What does matter, though, is that [project.scripts] doesn't support passing arguments - the entry point is only specified as path.to.module:function , which is expected not to take any arguments (although of course it can read `sys.argv`, which will be forwarded from the wrapper). (You can, however, specify any callable, not just a function; and it could be a nested attribute of some other object.)

Relevant documentation:

https://packaging.python.org/en/latest/guides/writing-pyproj...

As far as I'm aware, there's no formal name for this syntax, and only indirect documentation of what's supported - via Setuptools, which originated it:

https://setuptools.pypa.io/en/latest/userguide/entry_point.h...

You could fix this by just making functions that hard-code the name (or e.g. use `functools.partial` to get what you want). With that properly set up, any standards-compliant build backend will put the needed metadata into your wheel, and Pip and uv will both read that metadata and create the necessary wrapper when installing. (This is "recommended" behaviour for installers in the wheel standard, but not required IIRC.)

Then for example, on Linux, you end up with a wrapper script in the environment's bin folder, which looks like:

  #!/path/to/.venv/bin/python
  # -*- coding: utf-8 -*-
  import re
  import sys
  from main import run_botch_bot
  if __name__ == '__main__':
      sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
      sys.exit(run_botch_bot())
(On Windows, IIRC you get cookie-cutter compiled executables that read their own filename and use it to do the right thing, perhaps with a Python shim to do the import or something.)

(Perhaps you'd be interested in raising the documentation issue on https://github.com/pypa/packaging.python.org/issues ?)

Re: A year of uv: pros, cons, and should you migrate

#389
post #387

Earlier quoted context omitted.

>What do you do when you accidentally run pip install -r requirements.txt with the wrong .venv activated? As someone with a similar approach (not using requirements.txt, but using all the basic tools and not using any kind of workflow tool or sophisticated package manager), I don't understand the question. I just have a workflow where this isn't feasible. Why would the wrong venv be activated? I activate a venv accor…

> Why would the wrong venv be activated? Because when you activate a venv in a given terminal window it stays active until you deliberately deactivate it, and one terminal and one venv looks much like another. > I activate a venv according to the project I'm currently working on. So just manual discipline? It works (most of the time), but in my experience there's a "discipline budget"; every little niggle you have to…

>So just manual discipline? It works (most of the time), but in my experience there's a "discipline budget"; every little niggle you have to worry about manually saps your ability to think about the actual business problem.

>...but getting forced to update while you're in the middle of working on a feature...

I feel like trying to work on more than one project in the same session would require more such discipline.

>So how do you ensure that? pip dependency resolution is nondeterministic, dependency versions aren't locked by default and even if you lock the versions of your immediate dependencies, the versions of your transitive dependencies are still unlocked.

Ah, so this is really about lock files. I primarily develop libraries; if something breaks this way, I want to find out about it as soon as possible, so that I can advertise correct dependency ranges to my downstream.

The requirements.txt approach does, of course, allow you to list transitive dependencies explicitly, and pin everything. It's not a proper lock file (in the sense that it says nothing about supply chains, hashes etc.) but it does mean you get predictable versions of everything from PyPI (assuming your platform doesn't somehow change).

If I needed proper lock files, then I would take an approach that involves them, yes. Fortunately, it looks like I'd be able to take advantage of the PEP 751 standard if and when I need that.

>Putting pip inside Python was dumb and is another pitfall uv avoids/fixes.

Agreed completely! (Of course I was only using a venv so that I could have a separate, parallel version of Pip for testing.) Rather, the Pip bootstrapping system (which you can completely skip now, thanks to the `--python` hack) is dumb, along with all the other nonsense it's enabled (such as other programs trying to use Pip programmatically without a proper API, and without declaring it as a dependency; and such as empowering the Pip team to go so long without even as functional of a solution as `--python`; and such as making lots of people think that Python venv creation has to be much slower than it really does).

I'll be fixing this with Paper, too, of course.

Re: A year of uv: pros, cons, and should you migrate

#390

Earlier quoted context omitted.

>Then why even have the dependency file? Horses for courses. Dependency files - whether the project's requirements (or optional requirements, or in the future, other arbitrary dependency groups) in `pyproject.toml`, or a list in a `requirements.txt` file (the filename here is actually arbitrary) don't describe versions at all, in general. Their purpose is to describe what's needed to support the current code: its dir…

> Lockfiles are meant to describe the exact version of everything that should be in the environment to have exact reproducible behaviour (not just "working"), including transitive dependencies. It is wrong to specify the versions for your transitive dependencies except to achieve reproducible builds, as in CI or other situations. If a dependency fails to correctly describe their requirements in their pyproject.toml i…

>It is wrong to specify the versions for your transitive dependencies except to achieve reproducible builds

Yes, and this is why many people have both pyproject.toml and requirements.txt. pyproject.toml is meant to specify abstract, unresolved dependencies only.

>If your application only works with specific versions of dependencies and has bugs in others, that should be described in pyproject.toml.

That's quite literally not the design, if by "dependencies" you mean including transitive dependencies. pyproject.toml isn't there to enable reproducible builds. This is exactly why I included that speculation about the post-PEP751 future: currently we can "install applications", but with tools that aren't meant to handle exact application configurations.

> Reproducible builds for the purpose of testing or producing hash-identical wheels, or similar situations where the goal is producing an exact snapshot of a build, is the only reason to be using lockfiles.

Some application developers would say that, as far as they are concerned, the code "cannot run" except in the context of a reproducible build. If it works otherwise, that's an "upside", but they don't want to support it.

I think we're just going around in circles here.

Post reply on HN