Skip to content

Commit

Permalink
pep440: use structured errors for version specifiers
Browse files Browse the repository at this point in the history
This smoothes out the error handling to using something a bit more
structured. I did this because I intend to do the same for Version
(eventually), and it seems good to be consistent. It also lets us nest
errors a bit more easily and scrutinize the different error classes at a
glance.
  • Loading branch information
BurntSushi committed Jan 4, 2024
1 parent bb31d74 commit e657682
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 92 deletions.
41 changes: 39 additions & 2 deletions crates/pep440-rs/src/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ static VERSION_RE: Lazy<Regex> =
Lazy::new(|| Regex::new(&format!(r#"(?xi)^(?:\s*){VERSION_RE_INNER}(?:\s*)$"#)).unwrap());

/// One of `~=` `==` `!=` `<=` `>=` `<` `>` `===`
#[derive(Eq, PartialEq, Debug, Hash, Clone)]
#[derive(Eq, PartialEq, Debug, Hash, Clone, Copy)]
#[cfg_attr(feature = "pyo3", pyclass)]
pub enum Operator {
/// `== 1.2.3`
Expand Down Expand Up @@ -86,6 +86,41 @@ pub enum Operator {
GreaterThanEqual,
}

impl Operator {
/// Returns true if and only if this operator can be used in a version
/// specifier with a version containing a non-empty local segment.
///
/// Specifically, this comes from the "Local version identifiers are
/// NOT permitted in this version specifier." phrasing in the version
/// specifiers [spec].
///
/// [spec]: https://packaging.python.org/en/latest/specifications/version-specifiers/
pub(crate) fn is_local_compatible(&self) -> bool {
!matches!(
*self,
Operator::GreaterThan
| Operator::GreaterThanEqual
| Operator::LessThan
| Operator::LessThanEqual
| Operator::TildeEqual
| Operator::EqualStar
| Operator::NotEqualStar
)
}

/// Returns the wildcard version of this operator, if appropriate.
///
/// This returns `None` when this operator doesn't have an analogous
/// wildcard operator.
pub(crate) fn to_star(self) -> Option<Operator> {
match self {
Operator::Equal => Some(Operator::EqualStar),
Operator::NotEqual => Some(Operator::NotEqualStar),
_ => None,
}
}
}

impl FromStr for Operator {
type Err = String;

Expand Down Expand Up @@ -1372,7 +1407,9 @@ mod tests {
format!("Version `{version}` doesn't match PEP 440 rules")
);
assert_eq!(
VersionSpecifier::from_str(&format!("=={version}")).unwrap_err(),
VersionSpecifier::from_str(&format!("=={version}"))
.unwrap_err()
.to_string(),
format!("Version `{version}` doesn't match PEP 440 rules")
);
}
Expand Down
Loading

0 comments on commit e657682

Please sign in to comment.