diff --git a/crates/uv-resolver/src/resolver/mod.rs b/crates/uv-resolver/src/resolver/mod.rs index 966b39005e78b..8ecc115d8ddf6 100644 --- a/crates/uv-resolver/src/resolver/mod.rs +++ b/crates/uv-resolver/src/resolver/mod.rs @@ -1771,6 +1771,16 @@ impl ResolverState Result<()> { let context = TestContext::new("3.12"); @@ -9508,7 +9511,7 @@ fn universal_marker_propagation() -> Result<()> { .arg("requirements.in") .arg("-p") .arg("3.8") - .arg("--universal"), @r###" + .arg("--universal"), @r" success: true exit_code: 0 ----- stdout ----- @@ -9536,9 +9539,11 @@ fn universal_marker_propagation() -> Result<()> { # via jinja2 mpmath==1.3.0 # via sympy - networkx==3.2.1 + networkx==3.1 ; python_full_version < '3.9' + # via torch + networkx==3.2 ; python_full_version >= '3.9' # via torch - numpy==1.26.3 ; python_full_version < '3.9' + numpy==1.24.4 ; python_full_version < '3.9' # via torchvision numpy==1.26.4 ; python_full_version >= '3.9' # via torchvision @@ -9576,8 +9581,8 @@ fn universal_marker_propagation() -> Result<()> { ----- stderr ----- warning: The requested Python version 3.8 is not available; 3.12.[X] will be used to build dependencies instead. - Resolved 25 packages in [TIME] - "### + Resolved 26 packages in [TIME] + " ); Ok(()) @@ -17223,3 +17228,75 @@ fn pep_751_compile_no_emit_package() -> Result<()> { Ok(()) } + +/// Check that we reject versions that have an incompatible `Requires-Python`, but don't +/// have a `data-requires-python` key on the index page. +#[tokio::test] +async fn index_has_no_requires_python() -> Result<()> { + let context = TestContext::new_with_versions(&["3.9", "3.12"]); + let server = MockServer::start().await; + + // Unlike PyPI, https://download.pytorch.org/whl/cpu/networkx/ does not contain the + // `data-requires-python` key. + let networkx_page = r#" + + + +

Links for networkx

+ networkx-3.0-py3-none-any.whl
+ networkx-3.2.1-py3-none-any.whl
+ networkx-3.3-py3-none-any.whl
+ + + "#; + Mock::given(method("GET")) + .and(path("/networkx/")) + .respond_with(ResponseTemplate::new(200).set_body_raw(networkx_page, "text/html")) + .mount(&server) + .await; + + let requirements_in = context.temp_dir.child("requirements.in"); + requirements_in.write_str("networkx >3.0,<=3.3")?; + + uv_snapshot!(context + .pip_compile() + .env_remove(EnvVars::UV_EXCLUDE_NEWER) + .arg("--python") + .arg("3.9") + .arg("--index-url") + .arg(server.uri()) + .arg("requirements.in"), @r" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv via the following command: + # uv pip compile --cache-dir [CACHE_DIR] --python 3.9 requirements.in + networkx==3.2.1 + # via -r requirements.in + + ----- stderr ----- + Resolved 1 package in [TIME] + "); + + uv_snapshot!(context + .pip_compile() + .env_remove(EnvVars::UV_EXCLUDE_NEWER) + .arg("--python") + .arg("3.12") + .arg("--index-url") + .arg(server.uri()) + .arg("requirements.in"), @r" + success: true + exit_code: 0 + ----- stdout ----- + # This file was autogenerated by uv via the following command: + # uv pip compile --cache-dir [CACHE_DIR] --python 3.12 requirements.in + networkx==3.3 + # via -r requirements.in + + ----- stderr ----- + Resolved 1 package in [TIME] + "); + + Ok(()) +}