Backport changes from publish crates (#1739)

Backport of changes for the published new versions of pep440_rs and
pep508_rs to make it easier to keep them in sync.
This commit is contained in:
konsti 2024-02-20 19:33:27 +01:00 committed by GitHub
parent 8480842d3e
commit 2928c6e574
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 121 additions and 120 deletions

64
Cargo.lock generated
View file

@ -876,7 +876,7 @@ name = "distribution-filename"
version = "0.0.1"
dependencies = [
"insta",
"pep440_rs 0.4.0",
"pep440_rs",
"platform-tags",
"rkyv",
"serde",
@ -896,7 +896,7 @@ dependencies = [
"fs-err",
"itertools 0.12.1",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-tags",
"pypi-types",
@ -1588,7 +1588,7 @@ dependencies = [
"indoc",
"mailparse",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"platform-host",
"platform-info",
"plist",
@ -2156,16 +2156,6 @@ dependencies = [
"parking_lot_core 0.8.6",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core 0.9.9",
]
[[package]]
name = "parking_lot_core"
version = "0.8.6"
@ -2201,19 +2191,7 @@ checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pep440_rs"
version = "0.3.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "887f66cc62717ea72caac4f1eb4e6f392224da3ffff3f40ec13ab427802746d6"
dependencies = [
"lazy_static",
"regex",
"serde",
"unicode-width",
]
[[package]]
name = "pep440_rs"
version = "0.4.0"
version = "0.5.0"
dependencies = [
"indoc",
"once_cell",
@ -2228,13 +2206,13 @@ dependencies = [
[[package]]
name = "pep508_rs"
version = "0.2.3"
version = "0.4.2"
dependencies = [
"derivative",
"indoc",
"log",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pyo3",
"pyo3-log",
"regex",
@ -2496,7 +2474,7 @@ dependencies = [
"indoc",
"libc",
"memoffset",
"parking_lot 0.12.1",
"parking_lot",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
@ -2567,7 +2545,7 @@ dependencies = [
"insta",
"mailparse",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"regex",
"rkyv",
@ -2583,12 +2561,12 @@ dependencies = [
[[package]]
name = "pyproject-toml"
version = "0.8.1"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46d4a5e69187f23a29f8aa0ea57491d104ba541bc55f76552c2a74962aa20e04"
checksum = "3b80f889b6d413c3f8963a2c7db03f95dd6e1d85e1074137cb2013ea2faa8898"
dependencies = [
"indexmap 2.2.3",
"pep440_rs 0.3.12",
"pep440_rs",
"pep508_rs",
"serde",
"toml",
@ -2793,7 +2771,7 @@ dependencies = [
"insta",
"itertools 0.10.5",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"regex",
"serde",
@ -2882,7 +2860,7 @@ dependencies = [
"getrandom",
"http",
"hyper",
"parking_lot 0.11.2",
"parking_lot",
"reqwest",
"reqwest-middleware",
"retry-policies",
@ -4185,7 +4163,7 @@ dependencies = [
"miette",
"mimalloc",
"owo-colors 4.0.0",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-host",
"platform-tags",
@ -4292,7 +4270,7 @@ dependencies = [
"http",
"insta",
"install-wheel-rs",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-tags",
"pypi-types",
@ -4338,7 +4316,7 @@ dependencies = [
"itertools 0.12.1",
"mimalloc",
"owo-colors 4.0.0",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"petgraph",
"platform-host",
@ -4410,7 +4388,7 @@ dependencies = [
"futures",
"install-wheel-rs",
"nanoid",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-tags",
"pypi-types",
@ -4502,7 +4480,7 @@ dependencies = [
"futures",
"install-wheel-rs",
"once-map",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-tags",
"pypi-types",
@ -4536,7 +4514,7 @@ dependencies = [
"insta",
"itertools 0.12.1",
"once_cell",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"platform-host",
"platform-tags",
@ -4586,7 +4564,7 @@ dependencies = [
"once-map",
"once_cell",
"owo-colors 4.0.0",
"pep440_rs 0.4.0",
"pep440_rs",
"pep508_rs",
"petgraph",
"platform-host",
@ -4812,7 +4790,7 @@ checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
dependencies = [
"futures",
"js-sys",
"parking_lot 0.11.2",
"parking_lot",
"pin-utils",
"wasm-bindgen",
"wasm-bindgen-futures",

View file

@ -69,7 +69,7 @@ plist = { version = "1.6.0" }
pubgrub = { git = "https://github.com/zanieb/pubgrub", rev = "9b6d89cb8a0c7902815c8b2ae99106ba322ffb14" }
pyo3 = { version = "0.20.2" }
pyo3-log = { version = "0.9.0"}
pyproject-toml = { version = "0.8.1" }
pyproject-toml = { version = "0.10.0" }
rand = { version = "0.8.5" }
rayon = { version = "1.8.0" }
reflink-copy = { version = "0.1.14" }

View file

@ -1,6 +1,6 @@
[package]
name = "pep440_rs"
version = "0.4.0"
version = "0.5.0"
description = "A library for python version numbers and specifiers, implementing PEP 440"
license = "Apache-2.0 OR BSD-2-Clause"
include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "Readme.md", "pyproject.toml"]

View file

@ -16,7 +16,7 @@ let version = Version::from_str("1.19").unwrap();
let version_specifier = VersionSpecifier::from_str("==1.*").unwrap();
assert!(version_specifier.contains(&version));
let version_specifiers = parse_version_specifiers(">=1.16, <2.0").unwrap();
assert!(version_specifiers.iter().all(|specifier| specifier.contains(&version)));
assert!(version_specifiers.contains(&version));
```
In python (`pip install pep440_rs`):

View file

@ -9,7 +9,7 @@
//! let version_specifier = VersionSpecifier::from_str("== 1.*").unwrap();
//! assert!(version_specifier.contains(&version));
//! let version_specifiers = VersionSpecifiers::from_str(">=1.16, <2.0").unwrap();
//! assert!(version_specifiers.iter().all(|specifier| specifier.contains(&version)));
//! assert!(version_specifiers.contains(&version));
//! ```
//!
//! PEP 440 has a lot of unintuitive features, including:
@ -41,9 +41,7 @@ pub use {
LocalSegment, Operator, OperatorParseError, PreRelease, PreReleaseKind, Version,
VersionParseError, VersionPattern, VersionPatternParseError, MIN_VERSION,
},
version_specifier::{
parse_version_specifiers, VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError,
},
version_specifier::{VersionSpecifier, VersionSpecifiers, VersionSpecifiersParseError},
};
mod version;

View file

@ -2291,7 +2291,7 @@ fn parse_u64(bytes: &[u8]) -> Result<u64, VersionParseError> {
Ok(n)
}
/// The minimum version that can be represented by a [`Version`].
/// The minimum version that can be represented by a [`Version`]: `0a0.dev0`.
pub static MIN_VERSION: once_cell::sync::Lazy<Version> =
once_cell::sync::Lazy::new(|| Version::from_str("0a0.dev0").unwrap());

View file

@ -697,19 +697,8 @@ impl From<ParseErrorKind> for VersionSpecifierParseError {
}
}
/// Parses a list of specifiers such as `>= 1.0, != 1.3.*, < 2.0`.
///
/// I recommend using [`VersionSpecifiers::from_str`] instead.
///
/// ```rust
/// use std::str::FromStr;
/// use pep440_rs::{parse_version_specifiers, Version};
///
/// let version = Version::from_str("1.19").unwrap();
/// let version_specifiers = parse_version_specifiers(">=1.16, <2.0").unwrap();
/// assert!(version_specifiers.iter().all(|specifier| specifier.contains(&version)));
/// ```
pub fn parse_version_specifiers(
/// Parse a list of specifiers such as `>= 1.0, != 1.3.*, < 2.0`.
pub(crate) fn parse_version_specifiers(
spec: &str,
) -> Result<Vec<VersionSpecifier>, VersionSpecifiersParseError> {
let mut version_ranges = Vec::new();

View file

@ -1,6 +1,6 @@
[package]
name = "pep508_rs"
version = "0.2.3"
version = "0.4.2"
description = "A library for python dependency specifiers, better known as PEP 508"
include = ["/src", "Changelog.md", "License-Apache", "License-BSD", "Readme.md", "pyproject.toml"]
license = "Apache-2.0 OR BSD-2-Clause"
@ -30,9 +30,9 @@ rkyv = { workspace = true, features = ["strict"], optional = true }
serde = { workspace = true, features = ["derive"], optional = true }
serde_json = { workspace = true, optional = true }
thiserror = { workspace = true }
tracing = { workspace = true, features = ["log"] }
tracing = { workspace = true, optional = true }
unicode-width = { workspace = true }
url = { workspace = true, features = ["serde"] }
url = { workspace = true }
[dev-dependencies]
indoc = { version = "2.0.4" }
@ -41,7 +41,15 @@ serde_json = { version = "1.0.111" }
testing_logger = { version = "0.1.1" }
[features]
pyo3 = ["dep:pyo3", "pep440_rs/pyo3", "pyo3-log"]
rkyv = ["dep:rkyv", "pep440_rs/rkyv"]
serde = ["dep:serde", "pep440_rs/serde"]
pyo3 = ["dep:pyo3", "pep440_rs/pyo3", "pyo3-log", "tracing", "tracing/log"]
rkyv = ["dep:rkyv", "pep440_rs/rkyv", "uv-normalize/rkyv"]
serde = ["dep:serde", "pep440_rs/serde", "uv-normalize/serde", "url/serde"]
tracing = ["dep:tracing", "pep440_rs/tracing"]
# PEP 508 allows only URLs such as `foo @ https://example.org/foo` or `foo @ file:///home/ferris/foo`, and
# arguably does not allow relative paths in file URLs (`foo @ file://./foo`,
# `foo @ file:foo-3.0.0-py3-none-any.whl`, `foo @ file://foo-3.0.0-py3-none-any.whl`), as they are not part of the
# relevant RFCs, even though widely supported. Pip accepts relative file URLs and paths instead of urls
# (`foo @ ./foo-3.0.0-py3-none-any.whl`). The `non-pep508-features` controls whether these non-spec features will
# be supported.
non-pep508-extensions = []
default = []

View file

@ -14,7 +14,7 @@
//! assert_eq!(dependency_specification.extras, vec![ExtraName::from_str("security").unwrap(), ExtraName::from_str("tests").unwrap()]);
//! ```
#![deny(missing_docs)]
#![warn(missing_docs)]
#[cfg(feature = "pyo3")]
use std::collections::hash_map::DefaultHasher;
@ -738,7 +738,7 @@ fn parse_url(cursor: &mut Cursor, working_dir: Option<&Path>) -> Result<Verbatim
/// Create a `VerbatimUrl` to represent the requirement.
fn preprocess_url(
url: &str,
working_dir: Option<&Path>,
#[cfg_attr(not(feature = "non-pep508-extensions"), allow(unused))] working_dir: Option<&Path>,
cursor: &Cursor,
start: usize,
len: usize,
@ -752,20 +752,22 @@ fn preprocess_url(
// Transform, e.g., `/C:/Users/ferris/wheel-0.42.0.tar.gz` to `C:\Users\ferris\wheel-0.42.0.tar.gz`.
let path = normalize_url_path(path);
#[cfg(feature = "non-pep508-extensions")]
if let Some(working_dir) = working_dir {
VerbatimUrl::from_path(path, working_dir).with_given(url.to_string())
} else {
VerbatimUrl::from_absolute_path(path)
.map_err(|err| Pep508Error {
message: Pep508ErrorSource::UrlError(err),
start,
len,
input: cursor.to_string(),
})?
.with_given(url.to_string())
return Ok(
VerbatimUrl::from_path(path, working_dir).with_given(url.to_string())
);
}
}
VerbatimUrl::from_absolute_path(path)
.map_err(|err| Pep508Error {
message: Pep508ErrorSource::UrlError(err),
start,
len,
input: cursor.to_string(),
})?
.with_given(url.to_string())
}
// Ex) `https://download.pytorch.org/whl/torch_stable.html`
Some(_) => {
// Ex) `https://download.pytorch.org/whl/torch_stable.html`
@ -795,18 +797,19 @@ fn preprocess_url(
}
} else {
// Ex) `../editable/`
#[cfg(feature = "non-pep508-extensions")]
if let Some(working_dir) = working_dir {
VerbatimUrl::from_path(url, working_dir).with_given(url.to_string())
} else {
VerbatimUrl::from_absolute_path(url)
.map_err(|err| Pep508Error {
message: Pep508ErrorSource::UrlError(err),
start,
len,
input: cursor.to_string(),
})?
.with_given(url.to_string())
return Ok(VerbatimUrl::from_path(url, working_dir).with_given(url.to_string()));
}
VerbatimUrl::from_absolute_path(url)
.map_err(|err| Pep508Error {
message: Pep508ErrorSource::UrlError(err),
start,
len,
input: cursor.to_string(),
})?
.with_given(url.to_string())
};
Ok(url)
}
@ -1045,6 +1048,7 @@ pub fn python_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
/// Half of these tests are copied from <https://github.com/pypa/packaging/pull/624>
#[cfg(test)]
mod tests {
use std::env;
use std::str::FromStr;
use indoc::indoc;
@ -1629,4 +1633,26 @@ mod tests {
},
);
}
/// Check that the relative path support feature toggle works.
#[test]
fn non_pep508_paths() {
let requirements = &[
"foo @ file://./foo",
"foo @ file://foo-3.0.0-py3-none-any.whl",
"foo @ file:foo-3.0.0-py3-none-any.whl",
"foo @ ./foo-3.0.0-py3-none-any.whl",
];
let cwd = env::current_dir().unwrap();
for requirement in requirements {
assert_eq!(
Requirement::parse(requirement, &cwd).is_ok(),
cfg!(feature = "non-pep508-extensions"),
"{}: {:?}",
requirement,
Requirement::parse(requirement, &cwd)
);
}
}
}

View file

@ -21,7 +21,6 @@ use std::collections::HashSet;
use std::fmt::{Display, Formatter};
use std::ops::Deref;
use std::str::FromStr;
use tracing::warn;
use uv_normalize::ExtraName;
/// Ways in which marker evaluation can fail
@ -944,8 +943,11 @@ impl FromStr for MarkerTree {
impl MarkerTree {
/// Does this marker apply in the given environment?
pub fn evaluate(&self, env: &MarkerEnvironment, extras: &[ExtraName]) -> bool {
let mut reporter = |_kind, message, _marker_expression: &MarkerExpression| {
warn!("{}", message);
let mut reporter = |_kind, _message, _marker_expression: &MarkerExpression| {
#[cfg(feature = "tracing")]
{
tracing::warn!("{}", _message);
}
};
self.report_deprecated_options(&mut reporter);
match self {
@ -1347,7 +1349,6 @@ mod test {
use crate::marker::{MarkerEnvironment, StringVersion};
use crate::{MarkerExpression, MarkerOperator, MarkerTree, MarkerValue, MarkerValueString};
use indoc::indoc;
use log::Level;
use std::str::FromStr;
fn assert_err(input: &str, error: &str) {
@ -1443,6 +1444,7 @@ mod test {
}
#[test]
#[cfg(feature = "tracing")]
fn warnings() {
let env37 = env37();
testing_logger::setup();
@ -1453,7 +1455,7 @@ mod test {
captured_logs[0].body,
"Comparing two markers with each other doesn't make any sense, evaluating to false"
);
assert_eq!(captured_logs[0].level, Level::Warn);
assert_eq!(captured_logs[0].level, log::Level::Warn);
assert_eq!(captured_logs.len(), 1);
});
let non_pep440 = MarkerTree::from_str("python_version >= '3.9.'").unwrap();
@ -1465,7 +1467,7 @@ mod test {
evaluating to false: after parsing 3.9, found \".\" after it, \
which is not part of a valid version"
);
assert_eq!(captured_logs[0].level, Level::Warn);
assert_eq!(captured_logs[0].level, log::Level::Warn);
assert_eq!(captured_logs.len(), 1);
});
let string_string = MarkerTree::from_str("'b' >= 'a'").unwrap();
@ -1475,7 +1477,7 @@ mod test {
captured_logs[0].body,
"Comparing two quoted strings with each other doesn't make sense: 'b' >= 'a', evaluating to false"
);
assert_eq!(captured_logs[0].level, Level::Warn);
assert_eq!(captured_logs[0].level, log::Level::Warn);
assert_eq!(captured_logs.len(), 1);
});
let string_string = MarkerTree::from_str(r#"os.name == 'posix' and platform.machine == 'x86_64' and platform.python_implementation == 'CPython' and 'Ubuntu' in platform.version and sys.platform == 'linux'"#).unwrap();
@ -1484,7 +1486,7 @@ mod test {
let messages: Vec<_> = captured_logs
.iter()
.map(|message| {
assert_eq!(message.level, Level::Warn);
assert_eq!(message.level, log::Level::Warn);
&message.body
})
.collect();

View file

@ -35,7 +35,8 @@ impl VerbatimUrl {
Ok(Self { url, given: None })
}
/// Parse a URL from am absolute or relative path.
/// Parse a URL from an absolute or relative path.
#[cfg(feature = "non-pep508-extensions")] // PEP 508 arguably only allows absolute file URLs.
pub fn from_path(path: impl AsRef<str>, working_dir: impl AsRef<Path>) -> Self {
// Expand any environment variables.
let path = PathBuf::from(expand_env_vars(path.as_ref(), false).as_ref());

View file

@ -14,7 +14,7 @@ workspace = true
[dependencies]
pep440_rs = { path = "../pep440-rs", features = ["rkyv", "serde"] }
pep508_rs = { path = "../pep508-rs", features = ["rkyv", "serde"] }
pep508_rs = { path = "../pep508-rs", features = ["rkyv", "serde", "non-pep508-extensions"] }
uv-fs = { path = "../uv-fs" }
uv-normalize = { path = "../uv-normalize" }
uv-warnings = { path = "../uv-warnings" }

View file

@ -5,5 +5,5 @@ edition = "2021"
description = "Normalization for distribution, package and extra anmes"
[dependencies]
serde = { workspace = true, features = ["derive"] }
rkyv = { workspace = true, features = ["strict", "validation"] }
serde = { workspace = true, features = ["derive"], optional = true }
rkyv = { workspace = true, features = ["strict", "validation"], optional = true }

View file

@ -1,3 +1,4 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize};
use std::fmt;
use std::fmt::{Display, Formatter};
@ -13,7 +14,8 @@ use crate::{validate_and_normalize_owned, validate_and_normalize_ref, InvalidNam
/// See:
/// - <https://peps.python.org/pep-0685/#specification/>
/// - <https://packaging.python.org/en/latest/specifications/name-normalization/>
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize)]
#[cfg_attr(feature = "serde", derive(Serialize))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ExtraName(String);
impl ExtraName {
@ -31,6 +33,7 @@ impl FromStr for ExtraName {
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for ExtraName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where

View file

@ -90,6 +90,7 @@ fn is_normalized(name: impl AsRef<str>) -> Result<bool, InvalidNameError> {
Ok(true)
}
/// Invalid [`crate::PackageName`] or [`crate::ExtraName`].
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct InvalidNameError(String);

View file

@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::str::FromStr;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize};
use crate::{validate_and_normalize_owned, validate_and_normalize_ref, InvalidNameError};
@ -11,21 +12,14 @@ use crate::{validate_and_normalize_owned, validate_and_normalize_ref, InvalidNam
/// down to a single `-`, e.g., `---`, `.`, and `__` all get converted to just `-`.
///
/// See: <https://packaging.python.org/en/latest/specifications/name-normalization/>
#[derive(
Debug,
Clone,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
Serialize,
rkyv::Archive,
rkyv::Deserialize,
rkyv::Serialize,
#[cfg_attr(feature = "serde", derive(Serialize))]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
archive(check_bytes),
archive_attr(derive(Debug))
)]
#[archive(check_bytes)]
#[archive_attr(derive(Debug))]
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct PackageName(String);
impl PackageName {
@ -75,6 +69,7 @@ impl FromStr for PackageName {
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for PackageName {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where