uv
uv copied to clipboard
[Feature Request] Support `--upgrade-package` with a specific version
pip-compile --upgrade-package allows you to upgrade a specific package to a specific version instead of the latest version. For example, you can use the following command to update the django package to the latest version and requests to version 2.0.0:
pip-compile --upgrade-package django --upgrade-package requests==2.0.0
Currently, when using uv pip compile --upgrade-package requests==2.0.0, it produces the following error:
❯ uv --version
uv 0.1.10
❯ uv pip compile --upgrade-package requests==2.0.0
error: invalid value 'requests==2.0.0' for '--upgrade-package <UPGRADE_PACKAGE>': Not a valid package or extra name: "requests==2.0.0". Names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters.
For more information, try '--help'.
Additionally, pip-compile also supports the following form:
pip-compile --upgrade --upgrade-package 'requests<3.0'
It would be great if uv supports this feature as well.
Seems reasonable, thanks for the clear request :)
I don’t think I fully understand what the semantics of this are, especially for the variant that’s a bound rather than a specific version. What happens if the resolution can’t succeed using the given range / version? Is it ignored? (I’m hesitant to support the variant that takes a bound, it just adds a lot of complexity. Should that not be a constraint provided via a constraint file?)
I was also wondering if constraints could / should be used for this purpose. It does seem weird to provide arbitrary bounds on a single invocation.
In my scenario, this need often arises due to security reasons: the dependency package has discovered security vulnerabilities and needs to be upgraded, but we hope to stay as close as possible to the version already deployed in production in order to avoid introducing faults.
But, should / could that not be provided as a constraint file?
should it? for me I tend to do something like
pip-compile --output-file out.txt in.txt -P package~=X.Y
Where I treat the existing out.txt as the current state of the venv. When I run a command like this, I'm kinda asking a question:
- what package if any fits this constraint, given my current venv?
sometimes the answer is yes, with no issues (and write a new out.txt) sometimes the answer is no, unpin other packages (and fail to write a new out.txt) and maybe it's "irredeemable constraints" (and fail to write a new out.txt)
Usually my in.txt doesn't usually have version pins (that's what out.txt is for), unless I know for certain new versions would break something. Are you suggesting alternative to using bounded -P args is to temporarily add bounds to in.txt?
Any update on this one?
No updates right now.
What is the expected workflow for upgrading a package?
I'm in the process of migrating pip-tools to uv workflows. Previously, I'd use pip-compile requirements.in --upgrade-package boto3==x -o requirements.txt, which would take requirements.txt (as constriants) into account and make sure that boto3 is upgraded. If it can't be, it would upgrade necessary transient packages to make boto3 upgradeable to the version I had.
Right now, I use uv pip compile -c requirements.txt requirements.in -P boto3 -o requirements.txt, but it does nothing (there is newer version). If I remove boto3 manually from requirements.txt, it also does nothing (probably because of some transitive deps).
Conceptually, is this the same as --upgrade-package boto3 with boto3==x as a constraint? I'm trying to understand the semantics of --upgrade-package boto3==x.
Not quite, -U allows all requirements in the output to be updated but -P specifically operates with the new constraint and updates only the minimal set of requirements in the output to satisfy that additional constraint. If the new constraint can’t be satisfied with existing input constraints, pip compile errors.
Thanks! Though I'm wondering specifically about the use of -P with a version specifier.
Yep, so expectation of -P foo==1.2.3 is:
- apply an additional constraint of “foo==1.2.3”
- allow only output requirements necessary to meet this constraint to upgrade
- still meet all input constraints
Hi, just driving by to mention that this shows up when we try to have dependabot run updates using uv instead of pip-compile so a potential big impact from having it work exactly the same as pip-compile
https://github.com/astral-sh/uv/issues/1964
Dependabot will try to do exactly this
uv pip compile --build-isolation --output-file=requirements.txt \
--no-emit-index-url \
--no-annotate \
--no-header \
-P attrs==18.0.1 pyproject.toml
and uv complains with
error: invalid value 'attrs==13.0.1' for '--upgrade-package <UPGRADE_PACKAGE>': Not a valid package or extra name: "attrs==13.0.1". Names must start and end with a letter or digit and may only contain -, _, ., and alphanumeric characters.
That’s helpful to know, thanks. We should probably support it then.
It is my first time dearing to even look at a rust codebase but I would like to help. If you have a sample PR in which similar work has occurred, a few pointers or any guidance you think would help me find a way to send a PR for this, I'll take a shot at it. The carbon footprint of dependabot using pip-tools makes this work any effort.
My initial thinking is something like: change Upgrade in package_options.rs to Packages(FxHashSet<Requirement>) rather than Packages(FxHashSet<PackageName>). Then, at some point, iterate over those requirements and add them to constraints, then proceed as usual.