Skip to content

Commit

Permalink
Treat .pyw files as scripts in uv run on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
zanieb committed Aug 22, 2024
1 parent fa34466 commit 178d90c
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 4 deletions.
43 changes: 39 additions & 4 deletions crates/uv/src/commands/project/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -722,6 +722,8 @@ enum RunCommand {
Python(Vec<OsString>),
/// Execute a `python` script.
PythonScript(PathBuf, Vec<OsString>),
/// Execute a `pythonw` script (Windows only).
PythonGuiScript(PathBuf, Vec<OsString>),
/// Execute an external command.
External(OsString, Vec<OsString>),
/// Execute an empty command (in practice, `python` with no arguments).
Expand All @@ -734,6 +736,7 @@ impl RunCommand {
match self {
Self::Python(_) => Cow::Borrowed("python"),
Self::PythonScript(_, _) | Self::Empty => Cow::Borrowed("python"),
Self::PythonGuiScript(_, _) => Cow::Borrowed("pythonw"),
Self::External(executable, _) => executable.to_string_lossy(),
}
}
Expand All @@ -752,6 +755,25 @@ impl RunCommand {
process.args(args);
process
}
Self::PythonGuiScript(target, args) => {
let python_executable = interpreter.sys_executable();

// Use `pythonw.exe` if it exists, otherwise fall back to `python.exe`.
// See `install-wheel-rs::get_script_executable`.gd
let pythonw_executable = python_executable
.file_name()
.map(|name| {
let new_name = name.to_string_lossy().replace("python", "pythonw");
python_executable.with_file_name(new_name)
})
.filter(|path| path.is_file())
.unwrap_or_else(|| python_executable.to_path_buf());

let mut process = Command::new(&pythonw_executable);
process.arg(target);
process.args(args);
process
}
Self::External(executable, args) => {
let mut process = Command::new(executable);
process.args(args);
Expand Down Expand Up @@ -779,6 +801,13 @@ impl std::fmt::Display for RunCommand {
}
Ok(())
}
Self::PythonGuiScript(target, args) => {
write!(f, "pythonw {}", target.display())?;
for arg in args {
write!(f, " {}", arg.to_string_lossy())?;
}
Ok(())
}
Self::External(executable, args) => {
write!(f, "{}", executable.to_string_lossy())?;
for arg in args {
Expand All @@ -805,12 +834,18 @@ impl From<&ExternalCommand> for RunCommand {
let target_path = PathBuf::from(&target);
if target.eq_ignore_ascii_case("python") {
Self::Python(args.to_vec())
} else if target_path
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("py"))
&& target_path.exists()
} else if target_path.extension().is_some_and(|ext| {
ext.eq_ignore_ascii_case("py") || (cfg!(windows) && ext.eq_ignore_ascii_case("pyw"))
}) && target_path.exists()
{
Self::PythonScript(target_path, args.to_vec())
} else if cfg!(windows)
&& target_path
.extension()
.is_some_and(|ext| ext.eq_ignore_ascii_case("pyw"))
&& target_path.exists()
{
Self::PythonGuiScript(target_path, args.to_vec())
} else {
Self::External(
target.clone(),
Expand Down
40 changes: 40 additions & 0 deletions crates/uv/tests/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,46 @@ fn run_pep723_script() -> Result<()> {
Ok(())
}

/// Run a `.pyw` script. The script should be executed with `pythonw.exe`.
#[test]
#[cfg(windows)]
fn run_pythonw_script() -> Result<()> {
let context = TestContext::new("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(indoc! { r#"
[project]
name = "foo"
version = "1.0.0"
requires-python = ">=3.8"
dependencies = ["anyio"]
"#
})?;

let test_script = context.temp_dir.child("main.pyw");
test_script.write_str(indoc! { r#"
import anyio
"#
})?;

uv_snapshot!(context.filters(), context.run().arg("--preview").arg("main.pyw"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 6 packages in [TIME]
Prepared 4 packages in [TIME]
Installed 4 packages in [TIME]
+ anyio==4.3.0
+ foo==1.0.0 (from file://[TEMP_DIR]/)
+ idna==3.6
+ sniffio==1.3.1
"###);

Ok(())
}

/// Run a PEP 723-compatible script with `tool.uv` metadata.
#[test]
fn run_pep723_script_metadata() -> Result<()> {
Expand Down

0 comments on commit 178d90c

Please sign in to comment.