-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Deduplicate marker-specific dependencies in uv pip tree
output
#16078
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thanks for the pull request! Let me double check what we actually do at resolution-time, I'm not sure if we actually merge the specifiers as done here and I want to make sure we're doing the same thing. |
let (lower, upper, others) = specifiers.into_iter().fold( | ||
(None, None, Vec::new()), | ||
|(lower, upper, mut rest), spec| match *spec.operator() { | ||
Operator::GreaterThan | Operator::GreaterThanEqual => { | ||
(Some(Self::prefer_lower(lower, spec)), upper, rest) | ||
} | ||
Operator::LessThan | Operator::LessThanEqual => { | ||
(lower, Some(Self::prefer_upper(upper, spec)), rest) | ||
} | ||
_ => { | ||
rest.push(spec); | ||
(lower, upper, rest) | ||
} | ||
}, | ||
); | ||
|
||
let mut merged = lower | ||
.into_iter() | ||
.chain(upper) | ||
.chain(others) | ||
.collect::<Vec<_>>(); | ||
|
||
let mut seen = FxHashSet::default(); | ||
|
||
merged.retain(|spec| seen.insert(spec.to_string())); | ||
|
||
VersionSpecifiers::from_iter(merged) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a little wary of this. We almost certainly already have logic for combining version specifiers, though I'm not sure we can use it here, e.g.
uv/crates/uv-pep440/src/version_ranges.rs
Lines 13 to 22 in 3f83390
impl From<VersionSpecifiers> for Ranges<Version> { | |
/// Convert [`VersionSpecifiers`] to a PubGrub-compatible version range, using PEP 440 | |
/// semantics. | |
fn from(specifiers: VersionSpecifiers) -> Self { | |
let mut range = Self::full(); | |
for specifier in specifiers { | |
range = range.intersection(&Self::from(specifier)); | |
} | |
range | |
} |
It does look pretty clean though and is nicer than emitting redundant ranges, e.g., >=3.6, >=3.7
.
@konstin might have some thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From what I understand, this is a lossy conversion, e.g. once we intersect the specifiers into intervals for PubGrub we lose the exact shape of the original constraints, and there isn’t a reliable way to turn an arbitrary range back into a finite set of PEP 440 specifiers.
We could instead move the specifier-level deduplication that tightens bounds into the PEP 440 crate, exposing it for other potential use-cases and decluttering the pip tree
implementation. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah it makes sense that the PubGrub range would lose the original constraints.
I think I'll want to hear from @konsti, but either having it here until we have another use-case or moving it to the PEP 440 crate seems reasonable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd be using Ranges<Version>
, which gives us a canonical representation. The problem is that iirc we don't have a function yet for that conversion that handles prereleases correctly. There's another catch to this that while >=2.0.0
is technically larger than >=2.0.0a1
, the latter allows prereleases while the former doesn't.
I wouldn't put too much effort into making simplifications on VersionSpecifiers
work, Ranges
is a much better representation to work with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the amount of effort here for simplifying version specifiers seems pretty reasonable for user display if the only alternative is Ranges<Version>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd be using
Ranges<Version>
, which gives us a canonical representation. The problem is that iirc we don't have a function yet for that conversion that handles prereleases correctly. There's another catch to this that while>=2.0.0
is technically larger than>=2.0.0a1
, the latter allows prereleases while the former doesn't.I wouldn't put too much effort into making simplifications on
VersionSpecifiers
work,Ranges
is a much better representation to work with.
Can we track this in a separate issue? It seems like a bigger lift, and I wouldn't mind looking into it as a follow up.
scripts/packages/dup-target/src/dup_target.egg-info/dependency_links.txt
Outdated
Show resolved
Hide resolved
let (lower, upper, others) = specifiers.into_iter().fold( | ||
(None, None, Vec::new()), | ||
|(lower, upper, mut rest), spec| match *spec.operator() { | ||
Operator::GreaterThan | Operator::GreaterThanEqual => { | ||
(Some(Self::prefer_lower(lower, spec)), upper, rest) | ||
} | ||
Operator::LessThan | Operator::LessThanEqual => { | ||
(lower, Some(Self::prefer_upper(upper, spec)), rest) | ||
} | ||
_ => { | ||
rest.push(spec); | ||
(lower, upper, rest) | ||
} | ||
}, | ||
); | ||
|
||
let mut merged = lower | ||
.into_iter() | ||
.chain(upper) | ||
.chain(others) | ||
.collect::<Vec<_>>(); | ||
|
||
let mut seen = FxHashSet::default(); | ||
|
||
merged.retain(|spec| seen.insert(spec.to_string())); | ||
|
||
VersionSpecifiers::from_iter(merged) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we'd be using Ranges<Version>
, which gives us a canonical representation. The problem is that iirc we don't have a function yet for that conversion that handles prereleases correctly. There's another catch to this that while >=2.0.0
is technically larger than >=2.0.0a1
, the latter allows prereleases while the former doesn't.
I wouldn't put too much effort into making simplifications on VersionSpecifiers
work, Ranges
is a much better representation to work with.
This MR contains the following updates: | Package | Update | Change | |---|---|---| | [astral-sh/uv](https://github.com/astral-sh/uv) | minor | `0.8.22` -> `0.9.1` | MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot). **Proposed changes to behavior should be submitted there as MRs.** --- ### Release Notes <details> <summary>astral-sh/uv (astral-sh/uv)</summary> ### [`v0.9.1`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#091) [Compare Source](astral-sh/uv@0.9.0...0.9.1) Released on 2025-10-09. ##### Enhancements - Log Python choice in `uv init` ([#​16182](astral-sh/uv#16182)) - Fix `pylock.toml` config conflict error messages ([#​16211](astral-sh/uv#16211)) ##### Configuration - Add `UV_UPLOAD_HTTP_TIMEOUT` and respect `UV_HTTP_TIMEOUT` in uploads ([#​16040](astral-sh/uv#16040)) - Support `UV_WORKING_DIRECTORY` for setting `--directory` ([#​16125](astral-sh/uv#16125)) ##### Bug fixes - Allow missing `Scripts` directory ([#​16206](astral-sh/uv#16206)) - Fix handling of Python requests with pre-releases in ranges ([#​16208](astral-sh/uv#16208)) - Preserve comments on version bump ([#​16141](astral-sh/uv#16141)) - Retry all HTTP/2 errors ([#​16038](astral-sh/uv#16038)) - Treat deleted Windows registry keys as equivalent to missing ones ([#​16194](astral-sh/uv#16194)) - Ignore pre-release Python versions when a patch version is requested ([#​16210](astral-sh/uv#16210)) ##### Documentation - Document why uv discards upper bounds on `requires-python` ([#​15927](astral-sh/uv#15927)) - Document uv version environment variables were added in ([#​15196](astral-sh/uv#15196)) ### [`v0.9.0`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#090) [Compare Source](astral-sh/uv@0.8.24...0.9.0) Released on 2025-10-07. This breaking release is primarily motivated by the release of Python 3.14, which contains some breaking changes (we recommend reading the ["What's new in Python 3.14"](https://docs.python.org/3/whatsnew/3.14.html) page). uv may use Python 3.14 in cases where it previously used 3.13, e.g., if you have not pinned your Python version and do not have any Python versions installed on your machine. While we think this is uncommon, we prefer to be cautious. We've included some additional small changes that could break workflows. See our [Python 3.14](https://astral.sh/blog/python-3.14) blog post for some discussion of features we're excited about! There are no breaking changes to [`uv_build`](https://docs.astral.sh/uv/concepts/build-backend/). If you have an upper bound in your `[build-system]` table, you should update it. ##### Breaking changes - **Python 3.14 is now the default stable version** The default Python version has changed from 3.13 to 3.14. This applies to Python version installation when no Python version is requested, e.g., `uv python install`. By default, uv will use the system Python version if present, so this may not cause changes to general use of uv. For example, if Python 3.13 is installed already, then `uv venv` will use that version. If no Python versions are installed on a machine and automatic downloads are enabled, uv will now use 3.14 instead of 3.13, e.g., for `uv venv` or `uvx python`. This change will not affect users who are using a `.python-version` file to pin to a specific Python version. - **Allow use of free-threaded variants in Python 3.14+ without explicit opt-in** ([#​16142](astral-sh/uv#16142)) Previously, free-threaded variants of Python were considered experimental and required explicit opt-in (i.e., with `3.14t`) for usage. Now uv will allow use of free-threaded Python 3.14+ interpreters without explicit selection. The GIL-enabled build of Python will still be preferred, e.g., when performing an installation with `uv python install 3.14`. However, e.g., if a free-threaded interpreter comes before a GIL-enabled build on the `PATH`, it will be used. This change does not apply to free-threaded Python 3.13 interpreters, which will continue to require opt-in. - **Use Python 3.14 stable Docker images** ([#​16150](astral-sh/uv#16150)) Previously, the Python 3.14 images had an `-rc` suffix, e.g., `python:3.14-rc-alpine` or `python:3.14-rc-trixie`. Now, the `-rc` suffix has been removed to match the stable [upstream images](https://hub.docker.com/_/python). The `-rc` images tags will no longer be updated. This change should not break existing workflows. - **Upgrade Alpine Docker image to Alpine 3.22** Previously, the `uv:alpine` Docker image was based on Alpine 3.21. Now, this image is based on Alpine 3.22. The previous image can be recovered with `uv:alpine3.21` and will continue to be updated until a future release. - **Upgrade Debian Docker images to Debian 13 "Trixie"** Previously, the `uv:debian` and `uv:debian-slim` Docker images were based on Debian 12 "Bookworm". Now, these images are based on Debian 13 "Trixie". The previous images can be recovered with `uv:bookworm` and `uv:bookworm-slim` and will continue to be updated until a future release. - **Fix incorrect output path when a trailing `/` is used in `uv build`** ([#​15133](astral-sh/uv#15133)) When using `uv build` in a workspace, the artifacts are intended to be written to a `dist` directory in the workspace root. A bug caused workspace root determination to fail when the input path included a trailing `/` causing the `dist` directory to be placed in the child directory. This bug has been fixed in this release. For example, `uv build child/` is used, the output path will now be in `<workspace root>/dist/` rather than `<workspace root>/child/dist/`. ##### Python - Add CPython 3.14.0 - Add CPython 3.13.8 ##### Enhancements - Don't warn when a dependency is constrained by another dependency ([#​16149](astral-sh/uv#16149)) ##### Bug fixes - Fix `uv python upgrade / install` output when there is a no-op for one request ([#​16158](astral-sh/uv#16158)) - Surface pinned-version hint when `uv tool upgrade` can’t move the tool ([#​16081](astral-sh/uv#16081)) - Ban pre-release versions in `uv python upgrade` requests ([#​16160](astral-sh/uv#16160)) - Fix `uv python upgrade` replacement of installed binaries on pre-release to stable ([#​16159](astral-sh/uv#16159)) ##### Documentation - Update `uv pip compile` args in `layout.md` ([#​16155](astral-sh/uv#16155)) ### [`v0.8.24`](https://github.com/astral-sh/uv/releases/tag/0.8.24) [Compare Source](astral-sh/uv@0.8.23...0.8.24) #### Release Notes Released on 2025-10-06. ##### Enhancements - Emit a message on `cache clean` and `prune` when lock is held ([#​16138](astral-sh/uv#16138)) - Add `--force` flag for `uv cache prune` ([#​16137](astral-sh/uv#16137)) ##### Documentation - Fix example of bumping beta version without patch bump ([#​16132](astral-sh/uv#16132)) #### Install uv 0.8.24 ##### Install prebuilt binaries via shell script ```sh curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.24/uv-installer.sh | sh ``` ##### Install prebuilt binaries via powershell script ```sh powershell -ExecutionPolicy Bypass -c "irm https://github.com/astral-sh/uv/releases/download/0.8.24/uv-installer.ps1 | iex" ``` #### Download uv 0.8.24 | File | Platform | Checksum | | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | | [uv-aarch64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-apple-darwin.tar.gz.sha256) | | [uv-x86\_64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-apple-darwin.tar.gz.sha256) | | [uv-aarch64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-pc-windows-msvc.zip) | ARM64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-pc-windows-msvc.zip.sha256) | | [uv-i686-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-pc-windows-msvc.zip) | x86 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-pc-windows-msvc.zip.sha256) | | [uv-x86\_64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-pc-windows-msvc.zip.sha256) | | [uv-aarch64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-unknown-linux-gnu.tar.gz) | ARM64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-unknown-linux-gnu.tar.gz.sha256) | | [uv-i686-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-unknown-linux-gnu.tar.gz) | x86 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-powerpc64-unknown-linux-gnu.tar.gz) | PPC64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-powerpc64-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-powerpc64le-unknown-linux-gnu.tar.gz) | PPC64LE Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256) | | [uv-riscv64gc-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-riscv64gc-unknown-linux-gnu.tar.gz) | RISCV Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-riscv64gc-unknown-linux-gnu.tar.gz.sha256) | | [uv-s390x-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-s390x-unknown-linux-gnu.tar.gz) | S390x Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-s390x-unknown-linux-gnu.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-unknown-linux-gnu.tar.gz.sha256) | | [uv-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-armv7-unknown-linux-gnueabihf.tar.gz) | ARMv7 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-armv7-unknown-linux-gnueabihf.tar.gz.sha256) | | [uv-aarch64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-unknown-linux-musl.tar.gz) | ARM64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-aarch64-unknown-linux-musl.tar.gz.sha256) | | [uv-i686-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-unknown-linux-musl.tar.gz) | x86 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-i686-unknown-linux-musl.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-unknown-linux-musl.tar.gz) | x64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-x86_64-unknown-linux-musl.tar.gz.sha256) | | [uv-arm-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-arm-unknown-linux-musleabihf.tar.gz) | ARMv6 MUSL Linux (Hardfloat) | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-arm-unknown-linux-musleabihf.tar.gz.sha256) | | [uv-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-armv7-unknown-linux-musleabihf.tar.gz) | ARMv7 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.24/uv-armv7-unknown-linux-musleabihf.tar.gz.sha256) | ### [`v0.8.23`](https://github.com/astral-sh/uv/releases/tag/0.8.23) [Compare Source](astral-sh/uv@0.8.22...0.8.23) #### Release Notes Released on 2025-10-03. ##### Enhancements - Build `s390x` on stable Rust compiler version ([#​16082](astral-sh/uv#16082)) - Add `UV_SKIP_WHEEL_FILENAME_CHECK` to allow installing invalid wheels ([#​16046](astral-sh/uv#16046)) ##### Bug fixes - Avoid rejecting already-installed URL distributions with `--no-sources` ([#​16094](astral-sh/uv#16094)) - Confirm that the directory name is a valid Python install key during managed check ([#​16080](astral-sh/uv#16080)) - Ignore origin when comparing installed tools ([#​16055](astral-sh/uv#16055)) - Make cache control lookups robust to username ([#​16088](astral-sh/uv#16088)) - Re-order lock validation checks by severity ([#​16045](astral-sh/uv#16045)) - Remove tracking of inferred dependency conflicts ([#​15909](astral-sh/uv#15909)) - Respect `--no-color` on the CLI ([#​16044](astral-sh/uv#16044)) - Deduplicate marker-specific dependencies in `uv pip tree` output ([#​16078](astral-sh/uv#16078)) ##### Documentation - Document transparent x86\_64 emulation on aarch64 ([#​16041](astral-sh/uv#16041)) - Document why we ban URLs from index dependencies ([#​15929](astral-sh/uv#15929)) - Fix rendering of `_CONDA_ROOT` in reference ([#​16114](astral-sh/uv#16114)) - Windows arm64 and Linux RISC-V64 are Tier 2 supported ([#​16027](astral-sh/uv#16027)) #### Install uv 0.8.23 ##### Install prebuilt binaries via shell script ```sh curl --proto '=https' --tlsv1.2 -LsSf https://github.com/astral-sh/uv/releases/download/0.8.23/uv-installer.sh | sh ``` ##### Install prebuilt binaries via powershell script ```sh powershell -ExecutionPolicy Bypass -c "irm https://github.com/astral-sh/uv/releases/download/0.8.23/uv-installer.ps1 | iex" ``` #### Download uv 0.8.23 | File | Platform | Checksum | | --------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------- | | [uv-aarch64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-apple-darwin.tar.gz) | Apple Silicon macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-apple-darwin.tar.gz.sha256) | | [uv-x86\_64-apple-darwin.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-apple-darwin.tar.gz) | Intel macOS | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-apple-darwin.tar.gz.sha256) | | [uv-aarch64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-pc-windows-msvc.zip) | ARM64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-pc-windows-msvc.zip.sha256) | | [uv-i686-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-pc-windows-msvc.zip) | x86 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-pc-windows-msvc.zip.sha256) | | [uv-x86\_64-pc-windows-msvc.zip](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-pc-windows-msvc.zip) | x64 Windows | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-pc-windows-msvc.zip.sha256) | | [uv-aarch64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-unknown-linux-gnu.tar.gz) | ARM64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-unknown-linux-gnu.tar.gz.sha256) | | [uv-i686-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-unknown-linux-gnu.tar.gz) | x86 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-powerpc64-unknown-linux-gnu.tar.gz) | PPC64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-powerpc64-unknown-linux-gnu.tar.gz.sha256) | | [uv-powerpc64le-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-powerpc64le-unknown-linux-gnu.tar.gz) | PPC64LE Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-powerpc64le-unknown-linux-gnu.tar.gz.sha256) | | [uv-riscv64gc-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-riscv64gc-unknown-linux-gnu.tar.gz) | RISCV Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-riscv64gc-unknown-linux-gnu.tar.gz.sha256) | | [uv-s390x-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-s390x-unknown-linux-gnu.tar.gz) | S390x Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-s390x-unknown-linux-gnu.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-gnu.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-unknown-linux-gnu.tar.gz) | x64 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-unknown-linux-gnu.tar.gz.sha256) | | [uv-armv7-unknown-linux-gnueabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-armv7-unknown-linux-gnueabihf.tar.gz) | ARMv7 Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-armv7-unknown-linux-gnueabihf.tar.gz.sha256) | | [uv-aarch64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-unknown-linux-musl.tar.gz) | ARM64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-aarch64-unknown-linux-musl.tar.gz.sha256) | | [uv-i686-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-unknown-linux-musl.tar.gz) | x86 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-i686-unknown-linux-musl.tar.gz.sha256) | | [uv-x86\_64-unknown-linux-musl.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-unknown-linux-musl.tar.gz) | x64 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-x86_64-unknown-linux-musl.tar.gz.sha256) | | [uv-arm-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-arm-unknown-linux-musleabihf.tar.gz) | ARMv6 MUSL Linux (Hardfloat) | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-arm-unknown-linux-musleabihf.tar.gz.sha256) | | [uv-armv7-unknown-linux-musleabihf.tar.gz](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-armv7-unknown-linux-musleabihf.tar.gz) | ARMv7 MUSL Linux | [checksum](https://github.com/astral-sh/uv/releases/download/0.8.23/uv-armv7-unknown-linux-musleabihf.tar.gz.sha256) | </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this MR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box --- This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xMzIuNSIsInVwZGF0ZWRJblZlciI6IjQxLjE0My4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Resolves #16067
When we build the dependency graph we add an edge per
Requires-Dist
. If a package publishes multiple marker-guarded requirements (like pylint’sdill>=…
for different Python versions), more than one marker can evaluate to true at runtime, which gives us several edges pointing to the same installed package node.To avoid printing the package multiple times, we gather all edges targeting that node, pass them through a
Cursor
, and aggregate their requirement details before we print the dependency line. That aggregation does two things:I've added an integration test, namely
cargo test -p uv --test it --features pypi -- no_duplicate_dependencies_with_markers
exercises the new snapshot that installs pylint (with the real dill duplication scenario present in the original issue) and asserts the tree output, both with and without--show-version-specifiers
, now shows a single dill entry with the merged constraint.