Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions crates/uv-requirements-txt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,16 @@ impl RequirementsTxt {
end,
} => {
let filename = expand_env_vars(&filename);

// Skip remote constraints when in offline mode. This is primarily for reading
// lockfiles for preferences, where constraints aren't used anyway. When doing
// a real compile in offline mode, remote constraints would fail during resolution.
if (filename.starts_with("http://") || filename.starts_with("https://"))
&& client_builder.is_offline()
{
continue;
}

let sub_file =
if filename.starts_with("http://") || filename.starts_with("https://") {
PathBuf::from(filename.as_ref())
Expand Down
85 changes: 85 additions & 0 deletions crates/uv/tests/it/pip_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17850,3 +17850,88 @@ fn credentials_from_subdirectory() -> Result<()> {

Ok(())
}

/// Test that recompiling with a remote constraint in the output file works.
/// This reproduces a bug where uv would fail with "Network connectivity is disabled"
/// when trying to recompile a requirements.txt that contains a remote --constraint directive.
/// This is required for AWS MWAA workflows where the constraint must be in the output file.
#[tokio::test]
async fn compile_with_remote_constraint_in_output() -> Result<()> {
let context = TestContext::new("3.12");
let server = MockServer::start().await;

// Create a simple constraints file on the mock server
let constraints_content = "idna==3.3\n";
Mock::given(method("GET"))
.and(path("/constraints.txt"))
.respond_with(ResponseTemplate::new(200).set_body_raw(constraints_content, "text/plain"))
.mount(&server)
.await;

let requirements_in = context.temp_dir.child("requirements.in");
requirements_in.write_str(&format!(
"--constraint \"{}/constraints.txt\"\nanyio==3.7.0",
server.uri()
))?;

let requirements_txt = context.temp_dir.child("requirements.txt");

// First compilation - should work
uv_snapshot!(context.filters(), context.pip_compile()
.arg("requirements.in")
.arg("--output-file")
.arg("requirements.txt"), @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 --output-file requirements.txt
anyio==3.7.0
# via -r requirements.in
idna==3.3
# via
# -c http://[LOCALHOST]/constraints.txt
# anyio
sniffio==1.3.1
# via anyio

----- stderr -----
Resolved 3 packages in [TIME]
"###
);

// Append the constraint directive to the output file (simulating AWS MWAA requirement)
let mut output_content = fs_err::read_to_string(&requirements_txt)?;
output_content.push_str("--constraint \"");
output_content.push_str(&server.uri());
output_content.push_str("/constraints.txt\"\n");
fs_err::write(&requirements_txt, output_content)?;

// Second compilation - should also work (this is where the bug occurs)
// The bug is that uv tries to parse the constraint in offline mode when reading
// the output file for preferences, and fails with "Network connectivity is disabled"
uv_snapshot!(context.filters(), context.pip_compile()
.arg("requirements.in")
.arg("--output-file")
.arg("requirements.txt"), @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 --output-file requirements.txt
anyio==3.7.0
# via -r requirements.in
idna==3.3
# via
# -c http://[LOCALHOST]/constraints.txt
# anyio
sniffio==1.3.1
# via anyio

----- stderr -----
Resolved 3 packages in [TIME]
"###
);

Ok(())
}
Loading