From be91babd9f5428e975c6825f559d9456351b8129 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 1 Jul 2026 08:55:35 -0400 Subject: [PATCH] Avoid redundant pyproject parsing --- crates/uv-workspace/src/pyproject.rs | 42 ++++++++++------------------ crates/uv/tests/lock/lock.rs | 2 +- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/crates/uv-workspace/src/pyproject.rs b/crates/uv-workspace/src/pyproject.rs index c1aa4b0c134e5..848b46deca1b8 100644 --- a/crates/uv-workspace/src/pyproject.rs +++ b/crates/uv-workspace/src/pyproject.rs @@ -94,24 +94,21 @@ impl PyProjectToml { /// Parse a `PyProjectToml` from a raw TOML string. #[instrument("toml::from_str workspace", skip_all, fields(path = %_path.as_ref().display()))] pub fn from_string(raw: String, _path: impl AsRef) -> Result { - let sources_wire = - toml::from_str::(&raw).map_err(PyprojectTomlError::Toml)?; - let sources = sources_wire - .tool - .and_then(|tool| tool.uv) - .and_then(|uv| uv.sources) - .map(ToolUvSources::try_from) - .transpose()?; - - let mut pyproject: Self = toml::from_str(&raw).map_err(PyprojectTomlError::Toml)?; - if let Some(sources) = sources { - let tool_uv = pyproject - .tool - .as_mut() - .and_then(|tool| tool.uv.as_mut()) - .expect("tool.uv must exist when tool.uv.sources is present"); - tool_uv.sources = Some(sources); - } + let pyproject: Self = match toml::from_str(&raw) { + Ok(pyproject) => pyproject, + Err(error) => { + // Preserve the more specific source error if both parses would fail. + let sources = toml::from_str::(&raw) + .map_err(PyprojectTomlError::Toml)? + .tool + .and_then(|tool| tool.uv) + .and_then(|uv| uv.sources); + if let Some(sources) = sources { + ToolUvSources::try_from(sources)?; + } + return Err(PyprojectTomlError::Toml(error)); + } + }; Ok(Self { raw, ..pyproject }) } @@ -316,7 +313,6 @@ pub struct ToolUv { pydantic = { path = "/path/to/pydantic", editable = true } "# )] - #[serde(default, deserialize_with = "ignore_tool_uv_sources")] pub sources: Option, /// The indexes to use when resolving dependencies. @@ -712,14 +708,6 @@ pub struct ToolUv { #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] pub struct ToolUvSources(BTreeMap); -fn ignore_tool_uv_sources<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - serde::de::IgnoredAny::deserialize(deserializer)?; - Ok(None) -} - #[derive(Deserialize, Debug)] #[serde(rename_all = "kebab-case")] struct PyProjectTomlSourcesWire { diff --git a/crates/uv/tests/lock/lock.rs b/crates/uv/tests/lock/lock.rs index 32a2ce50f5888..535d4aec5305d 100644 --- a/crates/uv/tests/lock/lock.rs +++ b/crates/uv/tests/lock/lock.rs @@ -24750,7 +24750,7 @@ fn lock_multiple_sources_conflict() -> Result<()> { name = "project" version = "0.1.0" requires-python = ">=3.12" - dependencies = ["iniconfig"] + dependencies = 1 [tool.uv.sources] iniconfig = [