mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-21 15:52:15 +00:00
Better error message for missing space before semicolon in requirements (#1746)
PEP 508 requires a space between a URL and the semicolon separating it from the markers to disambiguate it from a url ending with a semicolon. This is easy to get wrong because the space is not required after a plain name of PEP 440 specifier. The new error message explicitly points out the missing space. Fixes #1637
This commit is contained in:
parent
db61d848a7
commit
a7513f4644
1 changed files with 27 additions and 7 deletions
|
@ -931,12 +931,16 @@ fn parse(cursor: &mut Cursor, working_dir: Option<&Path>) -> Result<Requirement,
|
|||
|
||||
// ( url_req | name_req )?
|
||||
let requirement_kind = match cursor.peek_char() {
|
||||
// url_req
|
||||
Some('@') => {
|
||||
cursor.next();
|
||||
Some(VersionOrUrl::Url(parse_url(cursor, working_dir)?))
|
||||
}
|
||||
// name_req
|
||||
Some('(') => parse_version_specifier_parentheses(cursor)?,
|
||||
// name_req
|
||||
Some('<' | '=' | '>' | '~' | '!') => parse_version_specifier(cursor)?,
|
||||
// No requirements / any version
|
||||
Some(';') | None => None,
|
||||
Some(other) => {
|
||||
// Rewind to the start of the version specifier, to see if the user added a URL without
|
||||
|
@ -963,6 +967,8 @@ fn parse(cursor: &mut Cursor, working_dir: Option<&Path>) -> Result<Requirement,
|
|||
}
|
||||
};
|
||||
|
||||
let requirement_end = cursor.pos;
|
||||
|
||||
// wsp*
|
||||
cursor.eat_whitespace();
|
||||
// quoted_marker?
|
||||
|
@ -976,12 +982,26 @@ fn parse(cursor: &mut Cursor, working_dir: Option<&Path>) -> Result<Requirement,
|
|||
// wsp*
|
||||
cursor.eat_whitespace();
|
||||
if let Some((pos, char)) = cursor.next() {
|
||||
if let Some(VersionOrUrl::Url(url)) = requirement_kind {
|
||||
// Unwrap safety: The `VerbatimUrl` we just parsed has a string source.
|
||||
if url.given().unwrap().ends_with(';') && marker.is_none() {
|
||||
return Err(Pep508Error {
|
||||
message: Pep508ErrorSource::String(
|
||||
"Missing space before ';', the end of the URL is ambiguous".to_string(),
|
||||
),
|
||||
start: requirement_end - ';'.len_utf8(),
|
||||
len: ';'.len_utf8(),
|
||||
input: cursor.to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
let message = if marker.is_none() {
|
||||
format!(r#"Expected end of input or ';', found '{char}'"#)
|
||||
} else {
|
||||
format!(r#"Expected end of input, found '{char}'"#)
|
||||
};
|
||||
return Err(Pep508Error {
|
||||
message: Pep508ErrorSource::String(if marker.is_none() {
|
||||
format!(r#"Expected end of input or ';', found '{char}'"#)
|
||||
} else {
|
||||
format!(r#"Expected end of input, found '{char}'"#)
|
||||
}),
|
||||
message: Pep508ErrorSource::String(message),
|
||||
start: pos,
|
||||
len: char.len_utf8(),
|
||||
input: cursor.to_string(),
|
||||
|
@ -1470,9 +1490,9 @@ mod tests {
|
|||
assert_err(
|
||||
r#"name @ https://example.com/; extra == 'example'"#,
|
||||
indoc! {"
|
||||
Expected end of input or ';', found 'e'
|
||||
Missing space before ';', the end of the URL is ambiguous
|
||||
name @ https://example.com/; extra == 'example'
|
||||
^"
|
||||
^"
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue