Allow reading `--with-requirements` from stdin in `uv add` and `uv run` (#10447)

For some reason this was banned when originally added (I did not see
discussion about it). I think it's fine to allow. With `uv run`, there's
a bit of nuance because we also allow the script to be read from stdin.
This commit is contained in:
Zanie Blue 2025-01-09 16:39:37 -06:00 committed by GitHub
parent 129a75e2d0
commit 22222e945f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 62 additions and 9 deletions

View File

@ -98,11 +98,6 @@ pub(crate) async fn add(
RequirementsSource::SetupCfg(_) => {
bail!("Adding requirements from a `setup.cfg` is not supported in `uv add`");
}
RequirementsSource::RequirementsTxt(path) => {
if path == Path::new("-") {
bail!("Reading requirements from stdin is not supported in `uv add`");
}
}
_ => {}
}
}

View File

@ -93,6 +93,7 @@ pub(crate) async fn run(
) -> anyhow::Result<ExitStatus> {
// These cases seem quite complex because (in theory) they should change the "current package".
// Let's ban them entirely for now.
let mut requirements_from_stdin: bool = false;
for source in &requirements {
match source {
RequirementsSource::PyprojectToml(_) => {
@ -106,13 +107,22 @@ pub(crate) async fn run(
}
RequirementsSource::RequirementsTxt(path) => {
if path == Path::new("-") {
bail!("Reading requirements from stdin is not supported in `uv run`");
requirements_from_stdin = true;
}
}
_ => {}
}
}
// Fail early if stdin is used for multiple purposes.
if matches!(
command,
Some(RunCommand::PythonStdin(..) | RunCommand::PythonGuiStdin(..))
) && requirements_from_stdin
{
bail!("Cannot read both requirements file and script from stdin");
}
// Initialize any shared state.
let state = SharedState::default();
@ -169,6 +179,9 @@ pub(crate) async fn run(
)?;
}
Pep723Item::Stdin(_) => {
if requirements_from_stdin {
bail!("Cannot read both requirements file and script from stdin");
}
writeln!(
printer.stderr(),
"Reading inline script metadata from `{}`",

View File

@ -1,3 +1,5 @@
#![allow(clippy::disallowed_types)]
use anyhow::Result;
use assert_cmd::assert::OutputAssertExt;
use assert_fs::prelude::*;
@ -4611,6 +4613,17 @@ fn add_requirements_file() -> Result<()> {
);
});
// Passing stdin should succeed
uv_snapshot!(context.filters(), context.add().arg("-r").arg("-").stdin(std::fs::File::open(requirements_txt)?), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved [N] packages in [TIME]
Audited [N] packages in [TIME]
"###);
// Passing a `setup.py` should fail.
uv_snapshot!(context.filters(), context.add().arg("-r").arg("setup.py"), @r###"
success: false

View File

@ -2124,19 +2124,51 @@ fn run_requirements_txt() -> Result<()> {
+ sniffio==1.3.1
"###);
// But reject `-` as a requirements file.
// Allow `-` for stdin.
uv_snapshot!(context.filters(), context.run()
.arg("--with-requirements")
.arg("-")
.arg("--with")
.arg("iniconfig")
.arg("main.py"), @r###"
.arg("main.py")
.stdin(std::fs::File::open(&requirements_txt)?), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 6 packages in [TIME]
Audited 4 packages in [TIME]
Resolved 2 packages in [TIME]
"###);
// But not in combination with reading the script from stdin
uv_snapshot!(context.filters(), context.run()
.arg("--with-requirements")
.arg("-")
// The script to run
.arg("-")
.stdin(std::fs::File::open(&requirements_txt)?), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Reading requirements from stdin is not supported in `uv run`
error: Cannot read both requirements file and script from stdin
"###);
uv_snapshot!(context.filters(), context.run()
.arg("--with-requirements")
.arg("-")
.arg("--script")
.arg("-")
.stdin(std::fs::File::open(&requirements_txt)?), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Cannot read both requirements file and script from stdin
"###);
Ok(())