From 410dc3357478f8dc729939cda9d27bb018df33bc Mon Sep 17 00:00:00 2001 From: John Mumm Date: Wed, 28 May 2025 12:36:18 +0200 Subject: [PATCH] Make `DisplaySafeUrlRef` Copy and other minor PR follow-ups (#13683) This PR implements a few review follow-ups from #13560. In particular, it * Makes `DisplaySafeUrlRef` implement `Copy` so that it can be passed by value. * Updates `to_string_with_credentials` methods with `displayable_with_credentials`, returning an `impl Display` instead of `String` for greater flexibility. * Updates the `DisplaySafeUrl` and `DisplaySafeUrlRef` `Debug` implementations to match the underlying `Url` `Debug` implementation (with the exception that credentials are masked). * Replaces an unnecessary `DisplaySafeUrl::from(Url::from_file_path` with `DisplaySafeUrl::from_file_path` --- crates/uv-auth/src/credentials.rs | 2 +- crates/uv-auth/src/keyring.rs | 30 +- crates/uv-auth/src/middleware.rs | 8 +- crates/uv-client/src/html.rs | 280 ++++++++++- crates/uv-pep508/src/verbatim_url.rs | 8 +- crates/uv-redacted/src/lib.rs | 61 ++- crates/uv-requirements-txt/src/lib.rs | 184 ++++++- ...xt__test__line-endings-whitespace.txt.snap | 32 +- ...ts_txt__test__parse-unix-bare-url.txt.snap | 144 +++++- ...ts_txt__test__parse-unix-editable.txt.snap | 192 +++++++- ...ments_txt__test__parse-whitespace.txt.snap | 32 +- ...txt__test__parse-windows-bare-url.txt.snap | 144 +++++- ...txt__test__parse-windows-editable.txt.snap | 192 +++++++- crates/uv/src/commands/publish.rs | 2 +- crates/uv/tests/it/lock.rs | 2 +- crates/uv/tests/it/show_settings.rs | 464 ++++++++++++++++-- 16 files changed, 1610 insertions(+), 167 deletions(-) diff --git a/crates/uv-auth/src/credentials.rs b/crates/uv-auth/src/credentials.rs index dfc05c5f2..b376857d0 100644 --- a/crates/uv-auth/src/credentials.rs +++ b/crates/uv-auth/src/credentials.rs @@ -145,7 +145,7 @@ impl Credentials { /// If a username is provided, it must match the login in the netrc file or [`None`] is returned. pub(crate) fn from_netrc( netrc: &Netrc, - url: &DisplaySafeUrlRef<'_>, + url: DisplaySafeUrlRef<'_>, username: Option<&str>, ) -> Option { let host = url.host_str()?; diff --git a/crates/uv-auth/src/keyring.rs b/crates/uv-auth/src/keyring.rs index 925a6756f..fbfc2e962 100644 --- a/crates/uv-auth/src/keyring.rs +++ b/crates/uv-auth/src/keyring.rs @@ -38,7 +38,7 @@ impl KeyringProvider { #[instrument(skip_all, fields(url = % url.to_string(), username))] pub async fn fetch( &self, - url: &DisplaySafeUrlRef<'_>, + url: DisplaySafeUrlRef<'_>, username: Option<&str>, ) -> Option { // Validate the request @@ -229,7 +229,7 @@ mod tests { let keyring = KeyringProvider::empty(); // Panics due to debug assertion; returns `None` in production let result = std::panic::AssertUnwindSafe( - keyring.fetch(&DisplaySafeUrlRef::from(&url), Some("user")), + keyring.fetch(DisplaySafeUrlRef::from(&url), Some("user")), ) .catch_unwind() .await; @@ -242,7 +242,7 @@ mod tests { let keyring = KeyringProvider::empty(); // Panics due to debug assertion; returns `None` in production let result = std::panic::AssertUnwindSafe( - keyring.fetch(&DisplaySafeUrlRef::from(&url), Some(url.username())), + keyring.fetch(DisplaySafeUrlRef::from(&url), Some(url.username())), ) .catch_unwind() .await; @@ -255,7 +255,7 @@ mod tests { let keyring = KeyringProvider::empty(); // Panics due to debug assertion; returns `None` in production let result = std::panic::AssertUnwindSafe( - keyring.fetch(&DisplaySafeUrlRef::from(&url), Some(url.username())), + keyring.fetch(DisplaySafeUrlRef::from(&url), Some(url.username())), ) .catch_unwind() .await; @@ -267,7 +267,7 @@ mod tests { let url = Url::parse("https://example.com").unwrap(); let url = DisplaySafeUrlRef::from(&url); let keyring = KeyringProvider::empty(); - let credentials = keyring.fetch(&url, Some("user")); + let credentials = keyring.fetch(url, Some("user")); assert!(credentials.await.is_none()); } @@ -277,7 +277,7 @@ mod tests { let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); assert_eq!( keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("user")) + .fetch(DisplaySafeUrlRef::from(&url), Some("user")) .await, Some(Credentials::basic( Some("user".to_string()), @@ -287,7 +287,7 @@ mod tests { assert_eq!( keyring .fetch( - &DisplaySafeUrlRef::from(&url.join("test").unwrap()), + DisplaySafeUrlRef::from(&url.join("test").unwrap()), Some("user") ) .await, @@ -303,7 +303,7 @@ mod tests { let url = Url::parse("https://example.com").unwrap(); let keyring = KeyringProvider::dummy([("other.com", "user", "password")]); let credentials = keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("user")) + .fetch(DisplaySafeUrlRef::from(&url), Some("user")) .await; assert_eq!(credentials, None); } @@ -318,7 +318,7 @@ mod tests { assert_eq!( keyring .fetch( - &DisplaySafeUrlRef::from(&url.join("foo").unwrap()), + DisplaySafeUrlRef::from(&url.join("foo").unwrap()), Some("user") ) .await, @@ -329,7 +329,7 @@ mod tests { ); assert_eq!( keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("user")) + .fetch(DisplaySafeUrlRef::from(&url), Some("user")) .await, Some(Credentials::basic( Some("user".to_string()), @@ -339,7 +339,7 @@ mod tests { assert_eq!( keyring .fetch( - &DisplaySafeUrlRef::from(&url.join("bar").unwrap()), + DisplaySafeUrlRef::from(&url.join("bar").unwrap()), Some("user") ) .await, @@ -355,7 +355,7 @@ mod tests { let url = Url::parse("https://example.com").unwrap(); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); let credentials = keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("user")) + .fetch(DisplaySafeUrlRef::from(&url), Some("user")) .await; assert_eq!( credentials, @@ -370,7 +370,7 @@ mod tests { async fn fetch_url_no_username() { let url = Url::parse("https://example.com").unwrap(); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "user", "password")]); - let credentials = keyring.fetch(&DisplaySafeUrlRef::from(&url), None).await; + let credentials = keyring.fetch(DisplaySafeUrlRef::from(&url), None).await; assert_eq!( credentials, Some(Credentials::basic( @@ -385,14 +385,14 @@ mod tests { let url = Url::parse("https://example.com").unwrap(); let keyring = KeyringProvider::dummy([(url.host_str().unwrap(), "foo", "password")]); let credentials = keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("bar")) + .fetch(DisplaySafeUrlRef::from(&url), Some("bar")) .await; assert_eq!(credentials, None); // Still fails if we have `foo` in the URL itself let url = Url::parse("https://foo@example.com").unwrap(); let credentials = keyring - .fetch(&DisplaySafeUrlRef::from(&url), Some("bar")) + .fetch(DisplaySafeUrlRef::from(&url), Some("bar")) .await; assert_eq!(credentials, None); } diff --git a/crates/uv-auth/src/middleware.rs b/crates/uv-auth/src/middleware.rs index c219a2cf6..15d20fd8a 100644 --- a/crates/uv-auth/src/middleware.rs +++ b/crates/uv-auth/src/middleware.rs @@ -508,7 +508,7 @@ impl AuthMiddleware { debug!("Checking netrc for credentials for {url}"); Credentials::from_netrc( netrc, - &url, + url, credentials .as_ref() .and_then(|credentials| credentials.username()), @@ -529,17 +529,17 @@ impl AuthMiddleware { if let Some(username) = credentials.and_then(|credentials| credentials.username()) { if let Some(index_url) = maybe_index_url { debug!("Checking keyring for credentials for index URL {}@{}", username, index_url); - keyring.fetch(&DisplaySafeUrlRef::from(index_url), Some(username)).await + keyring.fetch(DisplaySafeUrlRef::from(index_url), Some(username)).await } else { debug!("Checking keyring for credentials for full URL {}@{}", username, url); - keyring.fetch(&url, Some(username)).await + keyring.fetch(url, Some(username)).await } } else if matches!(auth_policy, AuthPolicy::Always) { if let Some(index_url) = maybe_index_url { debug!( "Checking keyring for credentials for index URL {index_url} without username due to `authenticate = always`" ); - keyring.fetch(&DisplaySafeUrlRef::from(index_url), None).await + keyring.fetch(DisplaySafeUrlRef::from(index_url), None).await } else { None } diff --git a/crates/uv-client/src/html.rs b/crates/uv-client/src/html.rs index e62da22d7..1b6b01347 100644 --- a/crates/uv-client/src/html.rs +++ b/crates/uv-client/src/html.rs @@ -279,7 +279,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -322,7 +336,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -368,7 +396,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://index.python.org/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "index.python.org", + ), + ), + port: None, + path: "/", + query: None, + fragment: None, + }, ), files: [ File { @@ -411,7 +453,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -454,7 +510,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -497,7 +567,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -538,7 +622,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -576,14 +674,28 @@ mod tests { "; let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap(); let result = SimpleHtml::parse(text, &base).unwrap(); - insta::assert_debug_snapshot!(result, @r" + insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [], } - "); + "#); } #[test] @@ -600,14 +712,28 @@ mod tests { "#; let base = Url::parse("https://download.pytorch.org/whl/jinja2/").unwrap(); let result = SimpleHtml::parse(text, &base).unwrap(); - insta::assert_debug_snapshot!(result, @r" + insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [], } - "); + "#); } #[test] @@ -627,7 +753,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -668,7 +808,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -710,7 +864,21 @@ mod tests { Ok( SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -753,7 +921,21 @@ mod tests { Ok( SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -813,7 +995,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://storage.googleapis.com/jax-releases/jax_cuda_releases.html, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "storage.googleapis.com", + ), + ), + port: None, + path: "/jax-releases/jax_cuda_releases.html", + query: None, + fragment: None, + }, ), files: [ File { @@ -881,7 +1077,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/flask/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "account.d.codeartifact.us-west-2.amazonaws.com", + ), + ), + port: None, + path: "/pypi/shared-packages-pypi/simple/flask/", + query: None, + fragment: None, + }, ), files: [ File { @@ -970,7 +1180,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://download.pytorch.org/whl/jinja2/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/jinja2/", + query: None, + fragment: None, + }, ), files: [ File { @@ -1029,7 +1253,21 @@ mod tests { insta::assert_debug_snapshot!(result, @r#" SimpleHtml { base: BaseUrl( - https://account.d.codeartifact.us-west-2.amazonaws.com/pypi/shared-packages-pypi/simple/flask/, + DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "account.d.codeartifact.us-west-2.amazonaws.com", + ), + ), + port: None, + path: "/pypi/shared-packages-pypi/simple/flask/", + query: None, + fragment: None, + }, ), files: [ File { diff --git a/crates/uv-pep508/src/verbatim_url.rs b/crates/uv-pep508/src/verbatim_url.rs index 5ef81f188..a7633bdcb 100644 --- a/crates/uv-pep508/src/verbatim_url.rs +++ b/crates/uv-pep508/src/verbatim_url.rs @@ -76,10 +76,8 @@ impl VerbatimUrl { let (path, fragment) = split_fragment(&path); // Convert to a URL. - let mut url = DisplaySafeUrl::from( - Url::from_file_path(path.clone()) - .map_err(|()| VerbatimUrlError::UrlConversion(path.to_path_buf()))?, - ); + let mut url = DisplaySafeUrl::from_file_path(path.clone()) + .map_err(|()| VerbatimUrlError::UrlConversion(path.to_path_buf()))?; // Set the fragment, if it exists. if let Some(fragment) = fragment { @@ -338,7 +336,7 @@ impl Pep508Url for VerbatimUrl { } fn displayable_with_credentials(&self) -> impl Display { - self.url.to_string_with_credentials() + self.url.displayable_with_credentials() } } diff --git a/crates/uv-redacted/src/lib.rs b/crates/uv-redacted/src/lib.rs index e0d72db4c..61b82a7f6 100644 --- a/crates/uv-redacted/src/lib.rs +++ b/crates/uv-redacted/src/lib.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::fmt::Write; +use std::fmt::{Debug, Display}; use std::ops::{Deref, DerefMut}; use std::str::FromStr; use url::Url; @@ -90,10 +90,10 @@ impl DisplaySafeUrl { let _ = self.0.set_password(None); } - /// Returns string representation without masking credentials. + /// Returns [`Display`] implementation that doesn't mask credentials. #[inline] - pub fn to_string_with_credentials(&self) -> String { - self.0.to_string() + pub fn displayable_with_credentials(&self) -> impl Display { + &self.0 } } @@ -111,15 +111,15 @@ impl DerefMut for DisplaySafeUrl { } } -impl std::fmt::Display for DisplaySafeUrl { +impl Display for DisplaySafeUrl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt_with_obfuscated_credentials(&self.0, f) + display_with_redacted_credentials(&self.0, f) } } -impl std::fmt::Debug for DisplaySafeUrl { +impl Debug for DisplaySafeUrl { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self}") + debug_with_redacted_credentials(&self.0, f) } } @@ -143,7 +143,10 @@ impl FromStr for DisplaySafeUrl { } } -fn fmt_with_obfuscated_credentials(url: &Url, mut f: W) -> std::fmt::Result { +fn display_with_redacted_credentials( + url: &Url, + f: &mut std::fmt::Formatter<'_>, +) -> std::fmt::Result { if url.password().is_none() && url.username() == "" { return write!(f, "{url}"); } @@ -176,6 +179,30 @@ fn fmt_with_obfuscated_credentials(url: &Url, mut f: W) -> std::fmt::R Ok(()) } +fn debug_with_redacted_credentials(url: &Url, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let (username, password) = if url.username() != "" && url.password().is_some() { + (url.username(), Some("****")) + } else if url.username() != "" { + ("****", None) + } else if url.password().is_some() { + ("", Some("****")) + } else { + ("", None) + }; + + f.debug_struct("DisplaySafeUrl") + .field("scheme", &url.scheme()) + .field("cannot_be_a_base", &url.cannot_be_a_base()) + .field("username", &username) + .field("password", &password) + .field("host", &url.host()) + .field("port", &url.port()) + .field("path", &url.path()) + .field("query", &url.query()) + .field("fragment", &url.fragment()) + .finish() +} + /// A wrapper around a [`url::Url`] ref that safely handles credentials for /// logging purposes. /// @@ -198,6 +225,7 @@ fn fmt_with_obfuscated_credentials(url: &Url, mut f: W) -> std::fmt::R /// // `Deref` implementation, you can still access the username and password /// assert_eq!(url.username(), "user"); /// assert_eq!(url.password(), Some("password")); +#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct DisplaySafeUrlRef<'a>(&'a Url); impl<'a> Deref for DisplaySafeUrlRef<'a> { @@ -208,15 +236,15 @@ impl<'a> Deref for DisplaySafeUrlRef<'a> { } } -impl std::fmt::Display for DisplaySafeUrlRef<'_> { +impl Display for DisplaySafeUrlRef<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - fmt_with_obfuscated_credentials(self.0, f) + display_with_redacted_credentials(self.0, f) } } -impl std::fmt::Debug for DisplaySafeUrlRef<'_> { +impl Debug for DisplaySafeUrlRef<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{self}") + debug_with_redacted_credentials(self.0, f) } } @@ -317,10 +345,13 @@ mod tests { } #[test] - fn to_string_with_credentials() { + fn displayable_with_credentials() { let url_str = "https://user:pass@pypi-proxy.fly.dev/basic-auth/simple"; let log_safe_url = DisplaySafeUrl::parse(url_str).unwrap(); - assert_eq!(&log_safe_url.to_string_with_credentials(), url_str); + assert_eq!( + &log_safe_url.displayable_with_credentials().to_string(), + url_str + ); } #[test] diff --git a/crates/uv-requirements-txt/src/lib.rs b/crates/uv-requirements-txt/src/lib.rs index 0d7f144bd..b734bf8a2 100644 --- a/crates/uv-requirements-txt/src/lib.rs +++ b/crates/uv-requirements-txt/src/lib.rs @@ -2052,14 +2052,34 @@ mod test { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///foo/bar, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/foo/bar", + query: None, + fragment: None, + }, install_path: "/foo/bar", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///foo/bar, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/foo/bar", + query: None, + fragment: None, + }, given: Some( "/foo/bar", ), @@ -2315,7 +2335,21 @@ mod test { editables: [], index_url: Some( VerbatimUrl { - url: https://test.pypi.org/simple/, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple/", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple/", ), @@ -2379,13 +2413,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.3.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.3.0-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.3.0-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.3.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.3.0-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.3.0-py3-none-any.whl", ), @@ -2408,13 +2462,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.2.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.2.0-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.2.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.2.0-py3-none-any.whl", ), @@ -2437,13 +2511,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.2.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.2.0-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.2.0-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.2.0-py3-none-any.whl", ), @@ -2470,13 +2564,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.2.0+local-py3-none-any.whl", ), @@ -2499,13 +2613,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.2.0+local-py3-none-any.whl", ), @@ -2528,13 +2662,33 @@ mod test { url: VerbatimParsedUrl { parsed_url: Path( ParsedPathUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, install_path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", ext: Wheel, }, ), verbatim: VerbatimUrl { - url: file:///importlib_metadata-8.2.0+local-py3-none-any.whl, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/importlib_metadata-8.2.0+local-py3-none-any.whl", + query: None, + fragment: None, + }, given: Some( "importlib_metadata-8.2.0+local-py3-none-any.whl", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__line-endings-whitespace.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__line-endings-whitespace.txt.snap index 80d7d6147..45b1cc43f 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__line-endings-whitespace.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__line-endings-whitespace.txt.snap @@ -39,7 +39,21 @@ RequirementsTxt { parsed_url: Git( ParsedGitUrl { url: GitUrl { - repository: https://github.com/pandas-dev/pandas.git, + repository: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "github.com", + ), + ), + port: None, + path: "/pandas-dev/pandas.git", + query: None, + fragment: None, + }, reference: DefaultBranch, precise: None, }, @@ -47,7 +61,21 @@ RequirementsTxt { }, ), verbatim: VerbatimUrl { - url: git+https://github.com/pandas-dev/pandas.git, + url: DisplaySafeUrl { + scheme: "git+https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "github.com", + ), + ), + port: None, + path: "/pandas-dev/pandas.git", + query: None, + fragment: None, + }, given: Some( "git+https://github.com/pandas-dev/pandas.git", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-bare-url.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-bare-url.txt.snap index 9886e6d8b..f2187a1a2 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-bare-url.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-bare-url.txt.snap @@ -10,14 +10,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black_editable", ), @@ -40,14 +60,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black_editable", ), @@ -74,14 +114,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "file:///scripts/packages/black_editable", ), @@ -104,14 +164,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), @@ -134,14 +214,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), @@ -164,14 +264,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-editable.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-editable.txt.snap index c211da005..222ab6b10 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-editable.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-unix-editable.txt.snap @@ -12,14 +12,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -49,14 +69,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -86,14 +126,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -123,14 +183,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -160,14 +240,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -190,14 +290,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable[d, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable[d", + query: None, + fragment: None, + }, install_path: "/editable[d", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable[d, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable[d", + query: None, + fragment: None, + }, given: Some( "./editable[d", ), @@ -220,14 +340,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -250,14 +390,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:///editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "/editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-whitespace.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-whitespace.txt.snap index 80d7d6147..45b1cc43f 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-whitespace.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-whitespace.txt.snap @@ -39,7 +39,21 @@ RequirementsTxt { parsed_url: Git( ParsedGitUrl { url: GitUrl { - repository: https://github.com/pandas-dev/pandas.git, + repository: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "github.com", + ), + ), + port: None, + path: "/pandas-dev/pandas.git", + query: None, + fragment: None, + }, reference: DefaultBranch, precise: None, }, @@ -47,7 +61,21 @@ RequirementsTxt { }, ), verbatim: VerbatimUrl { - url: git+https://github.com/pandas-dev/pandas.git, + url: DisplaySafeUrl { + scheme: "git+https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "github.com", + ), + ), + port: None, + path: "/pandas-dev/pandas.git", + query: None, + fragment: None, + }, given: Some( "git+https://github.com/pandas-dev/pandas.git", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-bare-url.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-bare-url.txt.snap index 9c801be04..72e1c8635 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-bare-url.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-bare-url.txt.snap @@ -10,14 +10,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black_editable", ), @@ -40,14 +60,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black_editable", ), @@ -74,14 +114,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black_editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black_editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black_editable", + query: None, + fragment: None, + }, given: Some( "file:///scripts/packages/black_editable", ), @@ -104,14 +164,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), @@ -134,14 +214,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), @@ -164,14 +264,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, install_path: "/scripts/packages/black editable", editable: false, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////scripts/packages/black%20editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//scripts/packages/black%20editable", + query: None, + fragment: None, + }, given: Some( "./scripts/packages/black editable", ), diff --git a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-editable.txt.snap b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-editable.txt.snap index 3f651d4ee..84ae22816 100644 --- a/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-editable.txt.snap +++ b/crates/uv-requirements-txt/src/snapshots/uv_requirements_txt__test__parse-windows-editable.txt.snap @@ -12,14 +12,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -49,14 +69,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -86,14 +126,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -123,14 +183,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -160,14 +240,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -190,14 +290,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable[d, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable[d", + query: None, + fragment: None, + }, install_path: "/editable[d", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable[d, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable[d", + query: None, + fragment: None, + }, given: Some( "./editable[d", ), @@ -220,14 +340,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), @@ -250,14 +390,34 @@ RequirementsTxt { url: VerbatimParsedUrl { parsed_url: Directory( ParsedDirectoryUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, install_path: "/editable", editable: true, virtual: false, }, ), verbatim: VerbatimUrl { - url: file:////editable, + url: DisplaySafeUrl { + scheme: "file", + cannot_be_a_base: false, + username: "", + password: None, + host: None, + port: None, + path: "//editable", + query: None, + fragment: None, + }, given: Some( "./editable", ), diff --git a/crates/uv/src/commands/publish.rs b/crates/uv/src/commands/publish.rs index 70cf053e7..843fc3f84 100644 --- a/crates/uv/src/commands/publish.rs +++ b/crates/uv/src/commands/publish.rs @@ -296,7 +296,7 @@ async fn gather_credentials( if let Some(username) = &username { debug!("Fetching password from keyring"); if let Some(keyring_password) = keyring_provider - .fetch(&DisplaySafeUrlRef::from(&publish_url), Some(username)) + .fetch(DisplaySafeUrlRef::from(&publish_url), Some(username)) .await .as_ref() .and_then(|credentials| credentials.password()) diff --git a/crates/uv/tests/it/lock.rs b/crates/uv/tests/it/lock.rs index a6cfafac2..447deb778 100644 --- a/crates/uv/tests/it/lock.rs +++ b/crates/uv/tests/it/lock.rs @@ -15811,7 +15811,7 @@ fn lock_explicit_default_index() -> Result<()> { DEBUG No workspace root found, using project root DEBUG Ignoring existing lockfile due to mismatched requirements for: `project==0.1.0` Requested: {Requirement { name: PackageName("anyio"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([]), index: None, conflict: None }, origin: None }} - Existing: {Requirement { name: PackageName("iniconfig"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([VersionSpecifier { operator: Equal, version: "2.0.0" }]), index: Some(IndexMetadata { url: Url(VerbatimUrl { url: https://test.pypi.org/simple, given: None }), format: Simple }), conflict: None }, origin: None }} + Existing: {Requirement { name: PackageName("iniconfig"), extras: [], groups: [], marker: true, source: Registry { specifier: VersionSpecifiers([VersionSpecifier { operator: Equal, version: "2.0.0" }]), index: Some(IndexMetadata { url: Url(VerbatimUrl { url: DisplaySafeUrl { scheme: "https", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("test.pypi.org")), port: None, path: "/simple", query: None, fragment: None }, given: None }), format: Simple }), conflict: None }, origin: None }} DEBUG Solving with installed Python version: 3.12.[X] DEBUG Solving with target Python version: >=3.12 DEBUG Adding direct dependency: project* diff --git a/crates/uv/tests/it/show_settings.rs b/crates/uv/tests/it/show_settings.rs index fd62ad7be..a2e6f3434 100644 --- a/crates/uv/tests/it/show_settings.rs +++ b/crates/uv/tests/it/show_settings.rs @@ -112,7 +112,21 @@ fn resolve_uv_toml() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -279,7 +293,21 @@ fn resolve_uv_toml() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -447,7 +475,21 @@ fn resolve_uv_toml() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -647,7 +689,21 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -976,7 +1032,21 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -1170,7 +1240,21 @@ fn resolve_index_url() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -1188,7 +1272,21 @@ fn resolve_index_url() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://test.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple", ), @@ -1357,7 +1455,21 @@ fn resolve_index_url() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://test.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple", ), @@ -1377,7 +1489,21 @@ fn resolve_index_url() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -1395,7 +1521,21 @@ fn resolve_index_url() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://test.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple", ), @@ -1588,7 +1728,21 @@ fn resolve_find_links() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://download.pytorch.org/whl/torch_stable.html, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl/torch_stable.html", + query: None, + fragment: None, + }, given: Some( "https://download.pytorch.org/whl/torch_stable.html", ), @@ -1943,7 +2097,21 @@ fn resolve_top_level() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://download.pytorch.org/whl, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl", + query: None, + fragment: None, + }, given: Some( "https://download.pytorch.org/whl", ), @@ -1961,7 +2129,21 @@ fn resolve_top_level() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://test.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple", ), @@ -2128,7 +2310,21 @@ fn resolve_top_level() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://download.pytorch.org/whl, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "download.pytorch.org", + ), + ), + port: None, + path: "/whl", + query: None, + fragment: None, + }, given: Some( "https://download.pytorch.org/whl", ), @@ -2146,7 +2342,21 @@ fn resolve_top_level() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://test.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "test.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://test.pypi.org/simple", ), @@ -3327,7 +3537,21 @@ fn resolve_both() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -3619,7 +3843,21 @@ fn resolve_config_file() -> anyhow::Result<()> { name: None, url: Pypi( VerbatimUrl { - url: https://pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://pypi.org/simple", ), @@ -4391,7 +4629,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -4411,7 +4663,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ), @@ -4578,7 +4844,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -4598,7 +4878,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ), @@ -4771,7 +5065,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -4791,7 +5099,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ), @@ -4959,7 +5281,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -4979,7 +5315,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ), @@ -5154,7 +5504,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -5174,7 +5538,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ), @@ -5342,7 +5720,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://cli.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "cli.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://cli.pypi.org/simple", ), @@ -5362,7 +5754,21 @@ fn index_priority() -> anyhow::Result<()> { name: None, url: Url( VerbatimUrl { - url: https://file.pypi.org/simple, + url: DisplaySafeUrl { + scheme: "https", + cannot_be_a_base: false, + username: "", + password: None, + host: Some( + Domain( + "file.pypi.org", + ), + ), + port: None, + path: "/simple", + query: None, + fragment: None, + }, given: Some( "https://file.pypi.org/simple", ),