mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-20 11:56:03 +00:00
Validate package and extra name (#290)
`PackageName` and `ExtraName` can now only be constructed from valid names. They share the same rules, so i gave them the same implementation. Constructors are split between `new` (owned) and `from_str` (borrowed), with the owned version avoiding allocations. Closes #279 --------- Co-authored-by: Zanie <contact@zanie.dev>
This commit is contained in:
parent
ea28b3d0d3
commit
81f380b10e
17 changed files with 258 additions and 171 deletions
|
|
@ -11,7 +11,7 @@
|
|||
//! let marker = r#"requests [security,tests] >= 2.8.1, == 2.8.* ; python_version > "3.8""#;
|
||||
//! let dependency_specification = Requirement::from_str(marker).unwrap();
|
||||
//! assert_eq!(dependency_specification.name.as_ref(), "requests");
|
||||
//! assert_eq!(dependency_specification.extras, Some(vec![ExtraName::new("security"), ExtraName::new("tests")]));
|
||||
//! assert_eq!(dependency_specification.extras, Some(vec![ExtraName::from_str("security").unwrap(), ExtraName::from_str("tests").unwrap()]));
|
||||
//! ```
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
|
@ -63,21 +63,13 @@ pub struct Pep508Error {
|
|||
#[derive(Debug, Error, Clone, Eq, PartialEq)]
|
||||
pub enum Pep508ErrorSource {
|
||||
/// An error from our parser
|
||||
#[error("{0}")]
|
||||
String(String),
|
||||
/// A url parsing error
|
||||
#[error(transparent)]
|
||||
UrlError(#[from] url::ParseError),
|
||||
}
|
||||
|
||||
impl Display for Pep508ErrorSource {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Pep508ErrorSource::String(string) => string.fmt(f),
|
||||
Pep508ErrorSource::UrlError(parse_err) => parse_err.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Pep508Error {
|
||||
/// Pretty formatting with underline
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
@ -568,7 +560,10 @@ fn parse_name(chars: &mut CharIter) -> Result<PackageName, Pep508Error> {
|
|||
});
|
||||
}
|
||||
}
|
||||
Some(_) | None => return Ok(PackageName::new(name)),
|
||||
Some(_) | None => {
|
||||
return Ok(PackageName::new(name)
|
||||
.expect("`PackageName` validation should match PEP 508 parsing"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -641,10 +636,16 @@ fn parse_extras(chars: &mut CharIter) -> Result<Option<Vec<ExtraName>>, Pep508Er
|
|||
// end or next identifier?
|
||||
match chars.next() {
|
||||
Some((_, ',')) => {
|
||||
extras.push(ExtraName::new(buffer));
|
||||
extras.push(
|
||||
ExtraName::new(buffer)
|
||||
.expect("`ExtraName` validation should match PEP 508 parsing"),
|
||||
);
|
||||
}
|
||||
Some((_, ']')) => {
|
||||
extras.push(ExtraName::new(buffer));
|
||||
extras.push(
|
||||
ExtraName::new(buffer)
|
||||
.expect("`ExtraName` validation should match PEP 508 parsing"),
|
||||
);
|
||||
break;
|
||||
}
|
||||
Some((pos, other)) => {
|
||||
|
|
@ -944,8 +945,11 @@ mod tests {
|
|||
let requests = Requirement::from_str(input).unwrap();
|
||||
assert_eq!(input, requests.to_string());
|
||||
let expected = Requirement {
|
||||
name: PackageName::new("requests"),
|
||||
extras: Some(vec![ExtraName::new("security"), ExtraName::new("tests")]),
|
||||
name: PackageName::from_str("requests").unwrap(),
|
||||
extras: Some(vec![
|
||||
ExtraName::from_str("security").unwrap(),
|
||||
ExtraName::from_str("tests").unwrap(),
|
||||
]),
|
||||
version_or_url: Some(VersionOrUrl::VersionSpecifier(
|
||||
[
|
||||
VersionSpecifier::new(
|
||||
|
|
@ -1086,7 +1090,7 @@ mod tests {
|
|||
#[test]
|
||||
fn error_extras1() {
|
||||
let numpy = Requirement::from_str("black[d]").unwrap();
|
||||
assert_eq!(numpy.extras, Some(vec![ExtraName::new("d")]));
|
||||
assert_eq!(numpy.extras, Some(vec![ExtraName::from_str("d").unwrap()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1094,7 +1098,10 @@ mod tests {
|
|||
let numpy = Requirement::from_str("black[d,jupyter]").unwrap();
|
||||
assert_eq!(
|
||||
numpy.extras,
|
||||
Some(vec![ExtraName::new("d"), ExtraName::new("jupyter")])
|
||||
Some(vec![
|
||||
ExtraName::from_str("d").unwrap(),
|
||||
ExtraName::from_str("jupyter").unwrap()
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1141,7 +1148,7 @@ mod tests {
|
|||
.unwrap();
|
||||
let url = "https://github.com/pypa/pip/archive/1.3.1.zip#sha1=da9234ee9982d4bbb3c72346a6de940a148ea686";
|
||||
let expected = Requirement {
|
||||
name: PackageName::new("pip"),
|
||||
name: PackageName::from_str("pip").unwrap(),
|
||||
extras: None,
|
||||
marker: None,
|
||||
version_or_url: Some(VersionOrUrl::Url(Url::parse(url).unwrap())),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue