mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-24 13:43:45 +00:00
Add support for uv init --script
(#7565)
This PR adds support for ```uv init --script```, as defined in issue #7402 (started working on this before I saw jbvsmo's PR). Wanted to highlight a few decisions I made that differ from the existing PR: 1. ```--script``` takes a path, instead of a path/name. This potentially leads to a little ambiguity (I can certainly elaborate in the docs, lmk!), but strictly allowing ```uv init --script path/to/script.py``` felt a little more natural than allowing for ```uv init --script path/to --name script.py``` (which I also thought would prompt more questions for users, such as should the name include the .py extension?) 2. The request is processed immediately in the ```init``` method, sharing logic in resolving which python version to use with ```uv add --script```. This made more sense to me — since scripts are meant to operate in isolation, they shouldn't consider the context of an encompassing package should one exist (I also think this decision makes the relative codepaths for scripts/packages easier to follow). 3. No readme — readme felt a little excessive for a script, but I can of course add it in! --------- Co-authored-by: João Bernardo Oliveira <jbvsmo@gmail.com>
This commit is contained in:
parent
a3abd89ab0
commit
6e9ecde9c2
10 changed files with 560 additions and 131 deletions
|
@ -65,7 +65,7 @@ impl Pep723Script {
|
|||
/// Reads a Python script and generates a default PEP 723 metadata table.
|
||||
///
|
||||
/// See: <https://peps.python.org/pep-0723/>
|
||||
pub async fn create(
|
||||
pub async fn init(
|
||||
file: impl AsRef<Path>,
|
||||
requires_python: &VersionSpecifiers,
|
||||
) -> Result<Self, Pep723Error> {
|
||||
|
@ -95,6 +95,51 @@ impl Pep723Script {
|
|||
})
|
||||
}
|
||||
|
||||
/// Create a PEP 723 script at the given path.
|
||||
pub async fn create(
|
||||
file: impl AsRef<Path>,
|
||||
requires_python: &VersionSpecifiers,
|
||||
existing_contents: Option<Vec<u8>>,
|
||||
) -> Result<(), Pep723Error> {
|
||||
let file = file.as_ref();
|
||||
|
||||
let script_name = file
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| Pep723Error::InvalidFilename(file.to_string_lossy().to_string()))?;
|
||||
|
||||
let default_metadata = indoc::formatdoc! {r#"
|
||||
requires-python = "{requires_python}"
|
||||
dependencies = []
|
||||
"#,
|
||||
};
|
||||
let metadata = serialize_metadata(&default_metadata);
|
||||
|
||||
let script = if let Some(existing_contents) = existing_contents {
|
||||
indoc::formatdoc! {r#"
|
||||
{metadata}
|
||||
{content}
|
||||
"#,
|
||||
content = String::from_utf8(existing_contents).map_err(|err| Pep723Error::Utf8(err.utf8_error()))?}
|
||||
} else {
|
||||
indoc::formatdoc! {r#"
|
||||
{metadata}
|
||||
|
||||
def main() -> None:
|
||||
print("Hello from {name}!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
"#,
|
||||
metadata = metadata,
|
||||
name = script_name,
|
||||
}
|
||||
};
|
||||
|
||||
Ok(fs_err::tokio::write(file, script).await?)
|
||||
}
|
||||
|
||||
/// Replace the existing metadata in the file with new metadata and write the updated content.
|
||||
pub async fn write(&self, metadata: &str) -> Result<(), Pep723Error> {
|
||||
let content = format!(
|
||||
|
@ -161,10 +206,12 @@ pub enum Pep723Error {
|
|||
Utf8(#[from] std::str::Utf8Error),
|
||||
#[error(transparent)]
|
||||
Toml(#[from] toml::de::Error),
|
||||
#[error("Invalid filename `{0}` supplied")]
|
||||
InvalidFilename(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
struct ScriptTag {
|
||||
pub struct ScriptTag {
|
||||
/// The content of the script before the metadata block.
|
||||
prelude: String,
|
||||
/// The metadata block.
|
||||
|
@ -202,7 +249,7 @@ impl ScriptTag {
|
|||
/// - Postlude: `import requests\n\nprint("Hello, World!")\n`
|
||||
///
|
||||
/// See: <https://peps.python.org/pep-0723/>
|
||||
fn parse(contents: &[u8]) -> Result<Option<Self>, Pep723Error> {
|
||||
pub fn parse(contents: &[u8]) -> Result<Option<Self>, Pep723Error> {
|
||||
// Identify the opening pragma.
|
||||
let Some(index) = FINDER.find(contents) else {
|
||||
return Ok(None);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue