Allow optional `=` for editables in `requirements.txt` (#10954)

## Summary

We allow this for all other argument flags; seems like an oversight.

Closes https://github.com/astral-sh/uv/issues/10941.
This commit is contained in:
Charlie Marsh 2025-01-24 21:55:51 -05:00 committed by GitHub
parent 1ef47aa1d5
commit a681905e12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 3 deletions

View File

@ -536,7 +536,19 @@ fn parse_entry(
end, end,
} }
} else if s.eat_if("-e") || s.eat_if("--editable") { } else if s.eat_if("-e") || s.eat_if("--editable") {
if s.eat_if('=') {
// Explicit equals sign.
} else if s.eat_if(char::is_whitespace) {
// Key and value are separated by whitespace instead.
s.eat_whitespace(); s.eat_whitespace();
} else {
let (line, column) = calculate_row_column(content, s.cursor());
return Err(RequirementsTxtParserError::Parser {
message: format!("Expected '=' or whitespace, found {:?}", s.peek()),
line,
column,
});
}
let source = if requirements_txt == Path::new("-") { let source = if requirements_txt == Path::new("-") {
None None
@ -851,10 +863,10 @@ fn parse_value<'a, T>(
while_pattern: impl Pattern<T>, while_pattern: impl Pattern<T>,
) -> Result<&'a str, RequirementsTxtParserError> { ) -> Result<&'a str, RequirementsTxtParserError> {
if s.eat_if('=') { if s.eat_if('=') {
// Explicit equals sign // Explicit equals sign.
Ok(s.eat_while(while_pattern).trim_end()) Ok(s.eat_while(while_pattern).trim_end())
} else if s.eat_if(char::is_whitespace) { } else if s.eat_if(char::is_whitespace) {
// Key and value are separated by whitespace instead // Key and value are separated by whitespace instead.
s.eat_whitespace(); s.eat_whitespace();
Ok(s.eat_while(while_pattern).trim_end()) Ok(s.eat_while(while_pattern).trim_end())
} else { } else {

View File

@ -1302,6 +1302,60 @@ fn install_editable_pep_508_requirements_txt() -> Result<()> {
"### "###
); );
requirements_txt.write_str(&indoc::formatdoc! {r"
--editable black[d] @ file://{workspace_root}/scripts/packages/black_editable
",
workspace_root = context.workspace_root.simplified_display(),
})?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.txt"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Audited 1 package in [TIME]
"###
);
requirements_txt.write_str(&indoc::formatdoc! {r"
--editable=black[d] @ file://{workspace_root}/scripts/packages/black_editable
",
workspace_root = context.workspace_root.simplified_display(),
})?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.txt"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Audited 1 package in [TIME]
"###
);
requirements_txt.write_str(&indoc::formatdoc! {r"
--editable= black[d] @ file://{workspace_root}/scripts/packages/black_editable
",
workspace_root = context.workspace_root.simplified_display(),
})?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r")
.arg("requirements.txt"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Audited 1 package in [TIME]
"###
);
Ok(()) Ok(())
} }