From e03f6c1fbc64b7183a2c5f3cdcc8684df060aac5 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Wed, 14 May 2025 15:19:34 -0400 Subject: [PATCH] Retain trailing comments after PEP 723 metadata block --- crates/uv-scripts/src/lib.rs | 16 ++++----- crates/uv/tests/it/edit.rs | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/crates/uv-scripts/src/lib.rs b/crates/uv-scripts/src/lib.rs index fa63ca3c00c42..2a530435a03d8 100644 --- a/crates/uv-scripts/src/lib.rs +++ b/crates/uv-scripts/src/lib.rs @@ -455,14 +455,9 @@ impl ScriptTag { // > consists of only a single #). let mut toml = vec![]; - // Extract the content that follows the metadata block. - let mut python_script = vec![]; - - while let Some(line) = lines.next() { + for line in lines { // Remove the leading `#`. let Some(line) = line.strip_prefix('#') else { - python_script.push(line); - python_script.extend(lines); break; }; @@ -474,8 +469,6 @@ impl ScriptTag { // Otherwise, the line _must_ start with ` `. let Some(line) = line.strip_prefix(' ') else { - python_script.push(line); - python_script.extend(lines); break; }; @@ -517,7 +510,12 @@ impl ScriptTag { // Join the lines into a single string. let prelude = prelude.to_string(); let metadata = toml.join("\n") + "\n"; - let postlude = python_script.join("\n") + "\n"; + let postlude = contents + .lines() + .skip(index + 1) + .collect::>() + .join("\n") + + "\n"; Ok(Some(Self { prelude, diff --git a/crates/uv/tests/it/edit.rs b/crates/uv/tests/it/edit.rs index 3ad1847348c0a..af671dea95c0a 100644 --- a/crates/uv/tests/it/edit.rs +++ b/crates/uv/tests/it/edit.rs @@ -5762,6 +5762,73 @@ fn add_script_settings() -> Result<()> { Ok(()) } +#[test] +fn add_script_trailing_comment_lines() -> Result<()> { + let context = TestContext::new("3.12"); + + let script = context.temp_dir.child("script.py"); + script.write_str(indoc! {r#" + # /// script + # requires-python = ">=3.11" + # dependencies = [ + # "requests<3", + # "rich", + # ] + # /// + # + # Additional description + + import requests + from rich.pretty import pprint + + resp = requests.get("https://peps.python.org/api/peps.json") + data = resp.json() + pprint([(k, v["title"]) for k, v in data.items()][:10]) + "#})?; + + uv_snapshot!(context.filters(), context.add().arg("anyio").arg("--script").arg("script.py"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Updated `script.py` + "###); + + let script_content = context.read("script.py"); + + insta::with_settings!({ + filters => context.filters(), + }, { + assert_snapshot!( + script_content, @r##" + # /// script + # requires-python = ">=3.11" + # dependencies = [ + # "anyio", + # "requests<3", + # "rich", + # ] + # /// + # + # Additional description + + import requests + from rich.pretty import pprint + + resp = requests.get("https://peps.python.org/api/peps.json") + data = resp.json() + pprint([(k, v["title"]) for k, v in data.items()][:10]) + "## + ); + }); + + // Adding to a script without a lockfile shouldn't create a lockfile. + assert!(!context.temp_dir.join("script.py.lock").exists()); + + Ok(()) +} + /// Add to a script without an existing metadata table. #[test] fn add_script_without_metadata_table() -> Result<()> {