Omit wheels from lockfile based on `--exclude-newer` (#12299)

## Summary

We respect `--exclude-newer` during resolution, but we weren't applying
it to individual _files_ when writing the lockfile. As a result, if
wheels were added to a distribution after its initial release, we'd end
up including them in the lockfile, even if they were uploaded after the
`--exclude-newer` date.

Closes https://github.com/astral-sh/uv/issues/12296.
This commit is contained in:
Charlie Marsh 2025-03-22 09:27:11 -07:00 committed by GitHub
parent 7ac6c6963d
commit ed0759fb45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 205 additions and 37 deletions

View File

@ -145,7 +145,7 @@ mod resolver {
let concurrency = Concurrency::default();
let config_settings = ConfigSettings::default();
let exclude_newer = Some(
jiff::civil::date(2024, 8, 8)
jiff::civil::date(2024, 9, 1)
.to_zoned(jiff::tz::TimeZone::UTC)
.unwrap()
.timestamp()

View File

@ -371,6 +371,10 @@ impl PrioritizedDist {
self.0.markers.or(implied_markers(&dist.filename));
}
}
// Track the hashes.
if !compatibility.is_excluded() {
self.0.hashes.extend(hashes);
}
// Track the highest-priority wheel.
if let Some((.., existing_compatibility)) = self.best_wheel() {
if compatibility.is_more_compatible(existing_compatibility) {
@ -379,7 +383,6 @@ impl PrioritizedDist {
} else {
self.0.best_wheel_index = Some(self.0.wheels.len());
}
self.0.hashes.extend(hashes);
self.0.wheels.push((dist, compatibility));
}
@ -394,6 +397,10 @@ impl PrioritizedDist {
if compatibility.is_compatible() {
self.0.markers = MarkerTree::TRUE;
}
// Track the hashes.
if !compatibility.is_excluded() {
self.0.hashes.extend(hashes);
}
// Track the highest-priority source.
if let Some((.., existing_compatibility)) = &self.0.source {
if compatibility.is_more_compatible(existing_compatibility) {
@ -402,7 +409,6 @@ impl PrioritizedDist {
} else {
self.0.source = Some((dist, compatibility));
}
self.0.hashes.extend(hashes);
}
/// Return the highest-priority distribution for the package version, if any.
@ -441,16 +447,19 @@ impl PrioritizedDist {
// wheel. We assume that all distributions have the same metadata for a given package
// version. If a compatible source distribution exists, we assume we can build it, but
// using the wheel is faster.
//
// (If the incompatible wheel should actually be ignored entirely, fall through to
// using the source distribution.)
(
Some((wheel, WheelCompatibility::Incompatible(_))),
Some((wheel, compatibility @ WheelCompatibility::Incompatible(_))),
Some((sdist, SourceDistCompatibility::Compatible(_))),
) => Some(CompatibleDist::IncompatibleWheel {
) if !compatibility.is_excluded() => Some(CompatibleDist::IncompatibleWheel {
sdist,
wheel,
prioritized: self,
}),
// Otherwise, if we have a source distribution, return it.
(None, Some((sdist, SourceDistCompatibility::Compatible(_)))) => {
(.., Some((sdist, SourceDistCompatibility::Compatible(_)))) => {
Some(CompatibleDist::SourceDist {
sdist,
prioritized: self,
@ -497,16 +506,25 @@ impl PrioritizedDist {
/// a built distribution with the best wheel in this prioritized dist.
pub fn built_dist(&self) -> Option<RegistryBuiltDist> {
let best_wheel_index = self.0.best_wheel_index?;
let wheels = self
.0
.wheels
.iter()
.map(|(wheel, _)| wheel.clone())
.collect();
// Remove any excluded wheels from the list of wheels, and adjust the wheel index to be
// relative to the filtered list.
let mut adjusted_wheels = Vec::with_capacity(self.0.wheels.len());
let mut adjusted_best_index = 0;
for (i, (wheel, compatibility)) in self.0.wheels.iter().enumerate() {
if compatibility.is_excluded() {
continue;
}
if i == best_wheel_index {
adjusted_best_index = adjusted_wheels.len();
}
adjusted_wheels.push(wheel.clone());
}
let sdist = self.0.source.as_ref().map(|(sdist, _)| sdist.clone());
Some(RegistryBuiltDist {
wheels,
best_wheel_index,
wheels: adjusted_wheels,
best_wheel_index: adjusted_best_index,
sdist,
})
}
@ -514,7 +532,12 @@ impl PrioritizedDist {
/// If this prioritized dist has an sdist, then this creates a source
/// distribution.
pub fn source_dist(&self) -> Option<RegistrySourceDist> {
let mut sdist = self.0.source.as_ref().map(|(sdist, _)| sdist.clone())?;
let mut sdist = self
.0
.source
.as_ref()
.filter(|(_, compatibility)| !compatibility.is_excluded())
.map(|(sdist, _)| sdist.clone())?;
assert!(
sdist.wheels.is_empty(),
"source distribution should not have any wheels yet"
@ -623,6 +646,11 @@ impl WheelCompatibility {
matches!(self, Self::Compatible(_, _, _))
}
/// Return `true` if the distribution is excluded.
pub fn is_excluded(&self) -> bool {
matches!(self, Self::Incompatible(IncompatibleWheel::ExcludeNewer(_)))
}
/// Return `true` if the current compatibility is more compatible than another.
///
/// Compatible wheels are always higher more compatible than incompatible wheels.
@ -650,6 +678,14 @@ impl SourceDistCompatibility {
matches!(self, Self::Compatible(_))
}
/// Return `true` if the distribution is excluded.
pub fn is_excluded(&self) -> bool {
matches!(
self,
Self::Incompatible(IncompatibleSource::ExcludeNewer(_))
)
}
/// Return the higher priority compatibility.
///
/// Compatible source distributions are always higher priority than incompatible source distributions.

View File

@ -26243,8 +26243,6 @@ fn lock_pytorch_local_preference() -> Result<()> {
{ name = "torch", version = "2.6.0+cpu", source = { registry = "https://astral-sh.github.io/pytorch-mirror/whl/cpu" }, marker = "sys_platform != 'darwin'" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/52/5b/76ca113a853b19c7b1da761f8a72cb6429b3bd0bf932537d8df4657f47c3/torchvision-0.21.0-1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:ffa2a16499508fe6798323e455f312c7c55f2a88901c9a7c0fb1efa86cf7e327", size = 2329878 },
{ url = "https://files.pythonhosted.org/packages/4e/fe/5e193353706dab96fe73ae100d5a633ff635ce310e0d92f3bc2958d075b1/torchvision-0.21.0-1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:7e9e9afa150e40cd2a8f0701c43cb82a8d724f512896455c0918b987f94b84a4", size = 2280711 },
{ url = "https://files.pythonhosted.org/packages/6e/1b/28f527b22d5e8800184d0bc847f801ae92c7573a8c15979d92b7091c0751/torchvision-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:97a5814a93c793aaf0179cfc7f916024f4b63218929aee977b645633d074a49f", size = 1784140 },
{ url = "https://files.pythonhosted.org/packages/36/63/0722e153fd27d64d5b0af45b5c8cb0e80b35a68cf0130303bc9a8bb095c7/torchvision-0.21.0-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:b578bcad8a4083b40d34f689b19ca9f7c63e511758d806510ea03c29ac568f7b", size = 7238673 },
{ url = "https://files.pythonhosted.org/packages/bb/ea/03541ed901cdc30b934f897060d09bbf7a98466a08ad1680320f9ce0cbe0/torchvision-0.21.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5083a5b1fec2351bf5ea9900a741d54086db75baec4b1d21e39451e00977f1b1", size = 14701186 },
@ -26616,3 +26614,93 @@ fn lock_invalid_fork_markers() -> Result<()> {
Ok(())
}
#[test]
fn lock_omit_wheels_exclude_newer() -> Result<()> {
let context = TestContext::new("3.12").with_exclude_newer("2024-08-01T00:00:00Z");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["pillow-avif-plugin"]
"#,
)?;
uv_snapshot!(context.filters(), context.lock(), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
");
let lock = context.read("uv.lock");
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r#"
version = 1
revision = 1
requires-python = ">=3.12"
[options]
exclude-newer = "2024-08-01T00:00:00Z"
[[package]]
name = "pillow-avif-plugin"
version = "1.4.6"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/eb/9c097e058c9d5bb7cd39b32730397d645856a81360b4e49cafe16ec1f358/pillow-avif-plugin-1.4.6.tar.gz", hash = "sha256:855cf50d03f6fc16e1fd5e364b3cea0b79f4bf90d39ff2123969735d851e08ba", size = 19632 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b2/f7/460c854c3f4a9802aabd0a25b4814a7e5902c776a6501498a4078bf2a0d3/pillow_avif_plugin-1.4.6-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e2087daa49881421a5e703fcff80aa2cbcb5a455cf73114ed5f0ea2a697794c8", size = 7980980 },
{ url = "https://files.pythonhosted.org/packages/f5/11/2f0fa7d135f91a8e34d9040b18a899d185776a642f5773ca33d45b0996ba/pillow_avif_plugin-1.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5bacc0802516f054f98d9f218ada17b2e8a756e35cb71e7401bb8422848fe796", size = 5743257 },
{ url = "https://files.pythonhosted.org/packages/24/b6/5a2fda66a192c0a372bcd7968c5914ccc6dcd48cd57b2f6cccba4587e209/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e74e53951228c3e6ff5141121bd2876e8aecdb27d5f12d01cc519258e0073d8b", size = 6431301 },
{ url = "https://files.pythonhosted.org/packages/ac/1d/2d6f816e15e56b053758fbd6d625fbd79b5cf22e775fce9967b83ede8c31/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37e1314500cec3457210f4c8a7583afe35751f076efa8122faa0f205403d645", size = 7984138 },
{ url = "https://files.pythonhosted.org/packages/86/36/32e9576c512fb53096ee050a112a12c6054c4e9c6ce2ec9e7e6f4d9d5d11/pillow_avif_plugin-1.4.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d643db246d6c07994fbb98b5fa6c6ae8f9b19b4ed24566bc06942b7dad10ad47", size = 8123272 },
{ url = "https://files.pythonhosted.org/packages/f0/5f/0bb9ec1910a5ece813ac6324b1d0f148cf71a0e5297ab8fcfce1e48a4ebe/pillow_avif_plugin-1.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:f262547edeec00ad287c8845ac6c9d7d822ef4b00d1832175c4c8fd692e34eba", size = 10564587 },
]
[[package]]
name = "project"
version = "0.1.0"
source = { virtual = "." }
dependencies = [
{ name = "pillow-avif-plugin" },
]
[package.metadata]
requires-dist = [{ name = "pillow-avif-plugin" }]
"#
);
});
// Re-run with `--locked`.
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
");
// Re-run with `--offline`. We shouldn't need a network connection to validate an
// already-correct lockfile with immutable metadata.
uv_snapshot!(context.filters(), context.lock().arg("--locked").arg("--offline").arg("--no-cache"), @r"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
");
Ok(())
}

View File

@ -16130,6 +16130,70 @@ fn respect_non_local_preference() -> Result<()> {
Ok(())
}
#[test]
fn omit_wheels_exclude_newer() -> Result<()> {
let context = TestContext::new("3.12").with_exclude_newer("2024-08-01T00:00:00Z");
let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str("pillow-avif-plugin")?;
uv_snapshot!(context
.pip_compile()
.arg("requirements.in")
.arg("--universal")
.arg("--generate-hashes"), @r"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] requirements.in --universal --generate-hashes
pillow-avif-plugin==1.4.6 \
--hash=sha256:0014a215e197c52520d3946f3704c8c0932a170cc5783f96d2385f55191dce29 \
--hash=sha256:07372b7740439cc26346d8e3995de1fd5c49a92ab307321b74b3e6305a7e0e49 \
--hash=sha256:09a7e4b00b18df55b9f34d4f031060ca46d8f5f5e0ba347dda600dcb5172e5f2 \
--hash=sha256:0e699ca8dcfee82732495e101401567184fed6ba10f17e7fb872c46415606ec7 \
--hash=sha256:2347399f2457e5efacec8fc9e446a5a90252b8723c6a47dc61e2353aa97e3e2e \
--hash=sha256:25d1dea0c496a49b17a336b271263ea76a4a0af19553565e95c4bb03281a4113 \
--hash=sha256:323804efe752cf4d15fdcf770749ba23d727f8ea94b95cfe42bec597f3b9bbbb \
--hash=sha256:334e1d39e8b3b4548db690df3735039378e96e1497fd8ba0e25a5e21561b7cf5 \
--hash=sha256:41a8c41b56a891adbcff30933009d475fdd649f2025d62ba59885975ed4379c0 \
--hash=sha256:450b34d19d88443e39b011e84b54433f7ccd6cf8774ed626e433ec3cc7d52924 \
--hash=sha256:56be2604b734caf23788922dbcc92d880d241d02b444c7a8367a65bb25b16aac \
--hash=sha256:584469ea7dedd8ca4f579917cf22f25e8ab980e1b98bbe212cbd7395f881cd42 \
--hash=sha256:5bacc0802516f054f98d9f218ada17b2e8a756e35cb71e7401bb8422848fe796 \
--hash=sha256:5c5e6575e0ca0cd292d459cf627a27a505f38a6edad6f35fd9c4bce4a2cccef3 \
--hash=sha256:5d3c1202e9e03b93ef5e385fcee917d73e23833618472e6416c0fc58b53ba8b8 \
--hash=sha256:60699d10679c8361690703b79abde4a2e7b8047540f0c58fd5da0ac672a15321 \
--hash=sha256:6556cbee2d755dc99a99a5a85c302393e58bcbbf675bc93fa9ab283904dadbfc \
--hash=sha256:6bc73ea62605c8725aba2422de1b546a5c4a6e5e73dcf66f9e22102249342d6b \
--hash=sha256:7d2e933e9b197e9a51c3fbfce389a70201fbce1b7c60172f790760217d7927f8 \
--hash=sha256:855cf50d03f6fc16e1fd5e364b3cea0b79f4bf90d39ff2123969735d851e08ba \
--hash=sha256:91537935612d8fb4b8f621a912ce0eb4e363fdf615d472b20a043a7a18efb461 \
--hash=sha256:963ce7b93340f235db5c7f16b46835c72681896052dcbf1652a01946e7b9103e \
--hash=sha256:a6f97ffc84cdce0926f86a2f4bee088e661f5f93bec9112adca281341f463479 \
--hash=sha256:b37e1314500cec3457210f4c8a7583afe35751f076efa8122faa0f205403d645 \
--hash=sha256:b4f08c341d8aed2d7762589fdd99c4d3e191d4976dab59516b522704a67a281d \
--hash=sha256:b7c2e4adcdf7341dc05f31f13d85b6c4eed0e08daafc836e7b3317df41074bab \
--hash=sha256:b95c477fc619a82a68800ff18599e2704aec6fcf9aa65898b02f0240feeb0af5 \
--hash=sha256:c1cd659136fca622a9324fa7efa56f711f2e576206754c284b80aa5504fb96e4 \
--hash=sha256:c8b9347a91acd183db302e198cf582127eb3de98ad185bf9aff773c99e415320 \
--hash=sha256:c96ee1d1b504a2efa80c9d6d3b71a9884c724dc34d6e67131a64678e09c7a81c \
--hash=sha256:ce89c26671cd0fcb7967e4be4098ae8775b93cc6376ecd523c815cb5a2146298 \
--hash=sha256:d643db246d6c07994fbb98b5fa6c6ae8f9b19b4ed24566bc06942b7dad10ad47 \
--hash=sha256:dec8a348e46266dd0bf20a6edd01b96b0a11042e8654d701444e4a5cebf7f44b \
--hash=sha256:df9a1e569543006abe0c534a3fa66ee1d72393644fd0d5bc74de57bfdb619573 \
--hash=sha256:e2087daa49881421a5e703fcff80aa2cbcb5a455cf73114ed5f0ea2a697794c8 \
--hash=sha256:e74e53951228c3e6ff5141121bd2876e8aecdb27d5f12d01cc519258e0073d8b \
--hash=sha256:f262547edeec00ad287c8845ac6c9d7d822ef4b00d1832175c4c8fd692e34eba \
--hash=sha256:fdd6ee615d948a2b68fd293f74a1a73d22e9d075f5d714b95a90ec2cb8da8de0
# via -r requirements.in
----- stderr -----
Resolved 1 package in [TIME]
");
Ok(())
}
/// See: <https://github.com/astral-sh/uv/issues/12260>
#[test]
fn compile_quotes() -> Result<()> {

View File

@ -1300,31 +1300,11 @@ source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/2d/eb/9c097e058c9d5bb7cd39b32730397d645856a81360b4e49cafe16ec1f358/pillow-avif-plugin-1.4.6.tar.gz", hash = "sha256:855cf50d03f6fc16e1fd5e364b3cea0b79f4bf90d39ff2123969735d851e08ba", size = 19632 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b2/f7/460c854c3f4a9802aabd0a25b4814a7e5902c776a6501498a4078bf2a0d3/pillow_avif_plugin-1.4.6-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e2087daa49881421a5e703fcff80aa2cbcb5a455cf73114ed5f0ea2a697794c8", size = 7980980 },
{ url = "https://files.pythonhosted.org/packages/26/ce/4e84b4caf933c4e938076b238e57245157a501d9a990451024d91e3dae9d/pillow_avif_plugin-1.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc3256fd23f5c7bef4bcc562db9d2cd04634a7b01dee41ea35e8e92a2334a949", size = 8016324 },
{ url = "https://files.pythonhosted.org/packages/f5/11/2f0fa7d135f91a8e34d9040b18a899d185776a642f5773ca33d45b0996ba/pillow_avif_plugin-1.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5bacc0802516f054f98d9f218ada17b2e8a756e35cb71e7401bb8422848fe796", size = 5743257 },
{ url = "https://files.pythonhosted.org/packages/ab/11/d26281b45864aed5a157896ecc77d2d941d072ffac840d2a2c4a81b9f1a1/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cbd9a1a45d982e346063ec4f4ce100021c565ee3102f9ff7f678019d5febada8", size = 12296355 },
{ url = "https://files.pythonhosted.org/packages/24/b6/5a2fda66a192c0a372bcd7968c5914ccc6dcd48cd57b2f6cccba4587e209/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e74e53951228c3e6ff5141121bd2876e8aecdb27d5f12d01cc519258e0073d8b", size = 6431301 },
{ url = "https://files.pythonhosted.org/packages/ac/1d/2d6f816e15e56b053758fbd6d625fbd79b5cf22e775fce9967b83ede8c31/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37e1314500cec3457210f4c8a7583afe35751f076efa8122faa0f205403d645", size = 7984138 },
{ url = "https://files.pythonhosted.org/packages/0e/05/a3750549f914763d34c9a1dc1c4d78e2fe5021ad26faa71892f18c34b073/pillow_avif_plugin-1.4.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3008acd3edf86e8e2291d40e9f9eae86f5140415431d21f219df5ca8e8210115", size = 14667148 },
{ url = "https://files.pythonhosted.org/packages/86/36/32e9576c512fb53096ee050a112a12c6054c4e9c6ce2ec9e7e6f4d9d5d11/pillow_avif_plugin-1.4.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:d643db246d6c07994fbb98b5fa6c6ae8f9b19b4ed24566bc06942b7dad10ad47", size = 8123272 },
{ url = "https://files.pythonhosted.org/packages/73/39/8955b693f0983d4f9326dae2df3135bb455011d474baee6ba9273ccf56ac/pillow_avif_plugin-1.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d0d96859d1ebfd7c6c8daa761a05ee9df0a70278ec3011b3b5c6e56ac4996fa7", size = 12489803 },
{ url = "https://files.pythonhosted.org/packages/b2/0f/327be9b4aca874d7d8b05b4e3300e55b3123611ee26f6ec1f055d1cb0f74/pillow_avif_plugin-1.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d1654a1048ad09b6e7553d4eb6e6bd3848be512bab2e283275585609dbda8b0", size = 14911324 },
{ url = "https://files.pythonhosted.org/packages/f0/5f/0bb9ec1910a5ece813ac6324b1d0f148cf71a0e5297ab8fcfce1e48a4ebe/pillow_avif_plugin-1.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:f262547edeec00ad287c8845ac6c9d7d822ef4b00d1832175c4c8fd692e34eba", size = 10564587 },
{ url = "https://files.pythonhosted.org/packages/3c/e2/eb6f75563b04188991bbe17d0c0350d9bb61886fa2660b749f34e555f3f2/pillow_avif_plugin-1.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1d43a5de556e2ab8437e9d8b07da96e968e0498cb3c0d448c34198c7bac0387c", size = 8016288 },
{ url = "https://files.pythonhosted.org/packages/46/c3/675d2de2a68761f5125751f724217d6177ca6e8e78b889db6207441b1e3d/pillow_avif_plugin-1.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8ce3fd54c76845c24dcd1cbc73fa5c72969df191bf7cd388a446f2f38342885c", size = 5676479 },
{ url = "https://files.pythonhosted.org/packages/21/33/7ee19bbbfb0568ea2f0dba644325e4111e65f7f7e99b9f1dcc956aa2d304/pillow_avif_plugin-1.4.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3c8d4f32a36ef4c345660a708067b6074dd380d0585589867333f7cb350bb9d", size = 12296248 },
{ url = "https://files.pythonhosted.org/packages/ce/40/51ba62d38a3ece90f5f22e641f0be952972a3c8238dd740e63c8d483dea3/pillow_avif_plugin-1.4.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f4563e5cd130016f8ea17602422b36abe4f63d2073ba98f2dbed42377b2f91c", size = 12214782 },
{ url = "https://files.pythonhosted.org/packages/bb/e2/7c6bce378c0d6c7a1a9f8a544e71e06a0a519c6d9ffc8e538dd015977a10/pillow_avif_plugin-1.4.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070b07e47012a3490ab56e62dd629cbe694240159df333f01692c3e5fb8acff8", size = 14394606 },
{ url = "https://files.pythonhosted.org/packages/31/33/a2f0785fcf20542fdfacea4390d3d1c5da26e7faeb10d9fb26cf374cd131/pillow_avif_plugin-1.4.6-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:57e883963205b7cfe2981ca98db6554c488fbff2b5a6751cfcf065c6e657a922", size = 14666959 },
{ url = "https://files.pythonhosted.org/packages/cd/12/be3b001225d9ed4b2e3119682315b4a51bf3e3114a24664096b73bd31512/pillow_avif_plugin-1.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ba1ae4dd323f019e0a1750555b02d91934724e4d556638baa60b5ca62e30f353", size = 12489897 },
{ url = "https://files.pythonhosted.org/packages/21/0a/6aa0f761308054b2aa7488ef9583c3125d1d2260b7d7482da0592a96ecaa/pillow_avif_plugin-1.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:73b840b612a6ce840e2206a9f097f4ad07c1ca4ed99a3b0d14444224daf55e88", size = 14911538 },
{ url = "https://files.pythonhosted.org/packages/19/80/3bdee7cd75ce7a1f20c2e1039d4a0e469185551032b95c68a58159b9fc9b/pillow_avif_plugin-1.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:a79fc89bae89be6bede9b4b01aff3967cd009c02edec1e70e6de8e52ef93b5fc", size = 10728675 },
{ url = "https://files.pythonhosted.org/packages/db/7e/fb4b950f16c3f43a030604a7f0672137c3c4a4b3a4fa98f3390dd88d0fa2/pillow_avif_plugin-1.4.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b1461731cde80ea246bce6ff87320367dbba206ee51a3370d99e679540dbcc17", size = 8016566 },
{ url = "https://files.pythonhosted.org/packages/1d/fb/0e3e2a252f2d92a8f453633144d35060d9bf53f5f5c7810f1fd0120bc1dd/pillow_avif_plugin-1.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fe32db84ba0c9d9b364e2b36a55620d6112133107f82854f19a4fdaa93fce66b", size = 5675393 },
{ url = "https://files.pythonhosted.org/packages/82/03/57b1c557ae05bf81cbcb2aa4cefd357861bdcfd1b055d53afd23d02902e8/pillow_avif_plugin-1.4.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ac4e238f172806b2f75a719895414ff8c67500ab0bfa691e53ee2a99cb85722", size = 14396630 },
{ url = "https://files.pythonhosted.org/packages/c2/00/12ec4d85453b85285b021e61bb027cadbf1bbb76b75d081ba0df7bc98d2a/pillow_avif_plugin-1.4.6-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:38a3934bcce34eb1f457434b336e4df8da1cf1eaea9306ca9f12ab5fa466e5a9", size = 14671480 },
{ url = "https://files.pythonhosted.org/packages/9d/9e/c922cdc8168c526201e3927fee37605b2d0df93dc9e6b2586f65cd6fd35a/pillow_avif_plugin-1.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70b4e26bc604d7af87a5e5605b3480db9832eab0dbcf0b86565a813716653cce", size = 14914496 },
{ url = "https://files.pythonhosted.org/packages/30/1e/315c22079058ffc2b8c6028cb18e33f7dc420ec56c806e8428419347f427/pillow_avif_plugin-1.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:10e9b2ef297a9825b461715359ae233d6518d9863c877a8652c14d6acae6e9f0", size = 10729094 },
]
[[package]]