mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 02:22:19 +00:00
Warn on unclosed script tags (#6704)
Should this be user-facing by default? It seems annoying because then it's unavoidable if you (for whatever reason) have an intentionally unclosed tag. Motivated by https://github.com/astral-sh/uv/issues/6700.
This commit is contained in:
parent
eb14056e9c
commit
a8f4e08d5b
2 changed files with 42 additions and 9 deletions
|
@ -5,10 +5,10 @@ use std::str::FromStr;
|
|||
use std::sync::LazyLock;
|
||||
|
||||
use memchr::memmem::Finder;
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use serde::Deserialize;
|
||||
use thiserror::Error;
|
||||
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use pep508_rs::PackageName;
|
||||
use pypi_types::VerbatimParsedUrl;
|
||||
use uv_settings::{GlobalOptions, ResolverInstallerOptions};
|
||||
|
@ -41,13 +41,14 @@ impl Pep723Script {
|
|||
};
|
||||
|
||||
// Extract the `script` tag.
|
||||
let Some(ScriptTag {
|
||||
let ScriptTag {
|
||||
prelude,
|
||||
metadata,
|
||||
postlude,
|
||||
}) = ScriptTag::parse(&contents)?
|
||||
else {
|
||||
return Ok(None);
|
||||
} = match ScriptTag::parse(&contents) {
|
||||
Ok(Some(tag)) => tag,
|
||||
Ok(None) => return Ok(None),
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
|
||||
// Parse the metadata.
|
||||
|
@ -152,6 +153,8 @@ pub struct ToolUv {
|
|||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Pep723Error {
|
||||
#[error("An opening tag (`# /// script`) was found without a closing tag (`# ///`). Ensure that every line between the opening and closing tags (including empty lines) starts with a leading `#`.")]
|
||||
UnclosedBlock,
|
||||
#[error(transparent)]
|
||||
Io(#[from] io::Error),
|
||||
#[error(transparent)]
|
||||
|
@ -272,7 +275,7 @@ impl ScriptTag {
|
|||
//
|
||||
// The latter `///` is the closing pragma
|
||||
let Some(index) = toml.iter().rev().position(|line| *line == "///") else {
|
||||
return Ok(None);
|
||||
return Err(Pep723Error::UnclosedBlock);
|
||||
};
|
||||
let index = toml.len() - index;
|
||||
|
||||
|
@ -364,7 +367,7 @@ fn serialize_metadata(metadata: &str) -> String {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{serialize_metadata, ScriptTag};
|
||||
use crate::{serialize_metadata, Pep723Error, ScriptTag};
|
||||
|
||||
#[test]
|
||||
fn missing_space() {
|
||||
|
@ -374,7 +377,10 @@ mod tests {
|
|||
# ///
|
||||
"};
|
||||
|
||||
assert_eq!(ScriptTag::parse(contents.as_bytes()).unwrap(), None);
|
||||
assert!(matches!(
|
||||
ScriptTag::parse(contents.as_bytes()),
|
||||
Err(Pep723Error::UnclosedBlock)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -388,7 +394,10 @@ mod tests {
|
|||
# ]
|
||||
"};
|
||||
|
||||
assert_eq!(ScriptTag::parse(contents.as_bytes()).unwrap(), None);
|
||||
assert!(matches!(
|
||||
ScriptTag::parse(contents.as_bytes()),
|
||||
Err(Pep723Error::UnclosedBlock)
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -359,6 +359,30 @@ fn run_pep723_script() -> Result<()> {
|
|||
╰─▶ Because there are no versions of add and you require add, we can conclude that your requirements are unsatisfiable.
|
||||
"###);
|
||||
|
||||
// If the script contains an unclosed PEP 723 tag, we should error.
|
||||
let test_script = context.temp_dir.child("main.py");
|
||||
test_script.write_str(indoc! { r#"
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = [
|
||||
# "iniconfig",
|
||||
# ]
|
||||
|
||||
# ///
|
||||
|
||||
import iniconfig
|
||||
"#
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.run().arg("--no-project").arg("main.py"), @r###"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: An opening tag (`# /// script`) was found without a closing tag (`# ///`). Ensure that every line between the opening and closing tags (including empty lines) starts with a leading `#`.
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue