mirror of https://github.com/astral-sh/uv
Add support for Windows legacy scripts via uv tool run (#12079)
## Summary Follow up to https://github.com/astral-sh/uv/pull/11888 with added support for uv tool run. Changes * Added functionality for running windows scripts in previous PR was moved from run.rs to uv_shell::runnable. * EXE was added as a supported type, this simplified integration across both uv run and uvx while retaining a backwards compatible behavior and properly prioritizing .exe over others. Name was adjusted to runnable as a result to better represent intent. ## Test Plan New tests added. ## Documentation Added new documentation.
This commit is contained in:
parent
82212bb439
commit
e096ab2411
|
|
@ -1,3 +1,4 @@
|
|||
pub mod runnable;
|
||||
mod shlex;
|
||||
pub mod windows;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
//! Utilities for running executables and scripts. Particularly in Windows.
|
||||
|
||||
use std::env::consts::EXE_EXTENSION;
|
||||
use std::ffi::OsStr;
|
||||
use std::path::Path;
|
||||
use std::process::Command;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum WindowsRunnable {
|
||||
/// Windows PE (.exe)
|
||||
Executable,
|
||||
/// `PowerShell` script (.ps1)
|
||||
PowerShell,
|
||||
/// Command Prompt NT script (.cmd)
|
||||
Command,
|
||||
/// Command Prompt script (.bat)
|
||||
Batch,
|
||||
}
|
||||
|
||||
impl WindowsRunnable {
|
||||
/// Returns a list of all supported Windows runnable types.
|
||||
fn all() -> &'static [Self] {
|
||||
&[
|
||||
Self::Executable,
|
||||
Self::PowerShell,
|
||||
Self::Command,
|
||||
Self::Batch,
|
||||
]
|
||||
}
|
||||
|
||||
/// Returns the extension for a given Windows runnable type.
|
||||
fn to_extension(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Executable => EXE_EXTENSION,
|
||||
Self::PowerShell => "ps1",
|
||||
Self::Command => "cmd",
|
||||
Self::Batch => "bat",
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines the runnable type from a given Windows file extension.
|
||||
fn from_extension(ext: &str) -> Option<Self> {
|
||||
match ext {
|
||||
EXE_EXTENSION => Some(Self::Executable),
|
||||
"ps1" => Some(Self::PowerShell),
|
||||
"cmd" => Some(Self::Command),
|
||||
"bat" => Some(Self::Batch),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [`Command`] to run the given type under the appropriate Windows runtime.
|
||||
fn as_command(&self, runnable_path: &Path) -> Command {
|
||||
match self {
|
||||
Self::Executable => Command::new(runnable_path),
|
||||
Self::PowerShell => {
|
||||
let mut cmd = Command::new("powershell");
|
||||
cmd.arg("-NoLogo").arg("-File").arg(runnable_path);
|
||||
cmd
|
||||
}
|
||||
Self::Command | Self::Batch => {
|
||||
let mut cmd = Command::new("cmd");
|
||||
cmd.arg("/q").arg("/c").arg(runnable_path);
|
||||
cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle console and legacy setuptools scripts for Windows.
|
||||
///
|
||||
/// Returns [`Command`] that can be used to invoke a supported runnable on Windows
|
||||
/// under the scripts path of an interpreter environment.
|
||||
pub fn from_script_path(script_path: &Path, runnable_name: &OsStr) -> Command {
|
||||
let script_path = script_path.join(runnable_name);
|
||||
|
||||
// Honor explicit extension if provided and recognized.
|
||||
if let Some(script_type) = script_path
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
.and_then(Self::from_extension)
|
||||
.filter(|_| script_path.is_file())
|
||||
{
|
||||
return script_type.as_command(&script_path);
|
||||
}
|
||||
|
||||
// Guess the extension when an explicit one is not provided.
|
||||
// We also add the extension when missing since for some types (e.g. PowerShell) it must be explicit.
|
||||
Self::all()
|
||||
.iter()
|
||||
.map(|script_type| {
|
||||
(
|
||||
script_type,
|
||||
script_path.with_extension(script_type.to_extension()),
|
||||
)
|
||||
})
|
||||
.find(|(_, script_path)| script_path.is_file())
|
||||
.map(|(script_type, script_path)| script_type.as_command(&script_path))
|
||||
.unwrap_or_else(|| Command::new(runnable_name))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
use std::env::VarError;
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::ffi::OsString;
|
||||
use std::fmt::Write;
|
||||
use std::io::Read;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
|
@ -33,6 +33,7 @@ use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
|||
use uv_resolver::Lock;
|
||||
use uv_scripts::Pep723Item;
|
||||
use uv_settings::PythonInstallMirrors;
|
||||
use uv_shell::runnable::WindowsRunnable;
|
||||
use uv_static::EnvVars;
|
||||
use uv_warnings::warn_user;
|
||||
use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceCache, WorkspaceError};
|
||||
|
|
@ -1126,58 +1127,6 @@ fn can_skip_ephemeral(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum WindowsScript {
|
||||
/// `PowerShell` script (.ps1)
|
||||
PowerShell,
|
||||
/// Command Prompt NT script (.cmd)
|
||||
Command,
|
||||
/// Command Prompt script (.bat)
|
||||
Batch,
|
||||
}
|
||||
|
||||
impl WindowsScript {
|
||||
/// Returns a list of all supported Windows script types.
|
||||
fn all() -> &'static [Self] {
|
||||
&[Self::PowerShell, Self::Command, Self::Batch]
|
||||
}
|
||||
|
||||
/// Returns the script extension for a given Windows script type.
|
||||
fn to_extension(&self) -> &'static str {
|
||||
match self {
|
||||
Self::PowerShell => "ps1",
|
||||
Self::Command => "cmd",
|
||||
Self::Batch => "bat",
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines the script type from a given Windows file extension.
|
||||
fn from_extension(ext: &str) -> Option<Self> {
|
||||
match ext {
|
||||
"ps1" => Some(Self::PowerShell),
|
||||
"cmd" => Some(Self::Command),
|
||||
"bat" => Some(Self::Batch),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a [`Command`] to run the given script under the appropriate Windows command.
|
||||
fn as_command(&self, script: &Path) -> Command {
|
||||
match self {
|
||||
Self::PowerShell => {
|
||||
let mut cmd = Command::new("powershell");
|
||||
cmd.arg("-NoLogo").arg("-File").arg(script);
|
||||
cmd
|
||||
}
|
||||
Self::Command | Self::Batch => {
|
||||
let mut cmd = Command::new("cmd");
|
||||
cmd.arg("/q").arg("/c").arg(script);
|
||||
cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum RunCommand {
|
||||
/// Execute `python`.
|
||||
|
|
@ -1239,37 +1188,6 @@ impl RunCommand {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handle legacy setuptools scripts for Windows.
|
||||
///
|
||||
/// Returns [`Command`] that can be used to run `.ps1`, `.cmd`, or `.bat` scripts on Windows.
|
||||
fn for_windows_script(interpreter: &Interpreter, executable: &OsStr) -> Command {
|
||||
let script_path = interpreter.scripts().join(executable);
|
||||
|
||||
// Honor explicit extension if provided and recognized.
|
||||
if let Some(script_type) = script_path
|
||||
.extension()
|
||||
.and_then(OsStr::to_str)
|
||||
.and_then(WindowsScript::from_extension)
|
||||
.filter(|_| script_path.is_file())
|
||||
{
|
||||
return script_type.as_command(&script_path);
|
||||
}
|
||||
|
||||
// Guess the extension when an explicit one is not provided.
|
||||
// We also add the extension when missing since for PowerShell it must be explicit.
|
||||
WindowsScript::all()
|
||||
.iter()
|
||||
.map(|script_type| {
|
||||
(
|
||||
script_type,
|
||||
script_path.with_extension(script_type.to_extension()),
|
||||
)
|
||||
})
|
||||
.find(|(_, script_path)| script_path.is_file())
|
||||
.map(|(script_type, script_path)| script_type.as_command(&script_path))
|
||||
.unwrap_or_else(|| Command::new(executable))
|
||||
}
|
||||
|
||||
/// Convert a [`RunCommand`] into a [`Command`].
|
||||
fn as_command(&self, interpreter: &Interpreter) -> Command {
|
||||
match self {
|
||||
|
|
@ -1386,7 +1304,7 @@ impl RunCommand {
|
|||
}
|
||||
Self::External(executable, args) => {
|
||||
let mut process = if cfg!(windows) {
|
||||
Self::for_windows_script(interpreter, executable)
|
||||
WindowsRunnable::from_script_path(interpreter.scripts(), executable).into()
|
||||
} else {
|
||||
Command::new(executable)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ use uv_python::{
|
|||
};
|
||||
use uv_requirements::{RequirementsSource, RequirementsSpecification};
|
||||
use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
|
||||
use uv_shell::runnable::WindowsRunnable;
|
||||
use uv_static::EnvVars;
|
||||
use uv_tool::{entrypoint_paths, InstalledTools};
|
||||
use uv_warnings::warn_user;
|
||||
|
|
@ -260,7 +261,12 @@ pub(crate) async fn run(
|
|||
let executable = from.executable();
|
||||
|
||||
// Construct the command
|
||||
let mut process = Command::new(executable);
|
||||
let mut process = if cfg!(windows) {
|
||||
WindowsRunnable::from_script_path(environment.scripts(), executable.as_ref()).into()
|
||||
} else {
|
||||
Command::new(executable)
|
||||
};
|
||||
|
||||
process.args(args);
|
||||
|
||||
// Construct the `PATH` environment variable.
|
||||
|
|
|
|||
|
|
@ -4560,7 +4560,7 @@ fn run_windows_legacy_scripts() -> Result<()> {
|
|||
Audited 1 package in [TIME]
|
||||
"###);
|
||||
|
||||
// Test without explicit extension (.ps1 should be used)
|
||||
// Test without explicit extension (.ps1 should be used) as there's no .exe available.
|
||||
uv_snapshot!(context.filters(), context.run().arg("custom_pydoc"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
|
|
|
|||
|
|
@ -2259,3 +2259,323 @@ fn tool_run_with_script_and_from_script() {
|
|||
hint: If you meant to run a command from the `script-py` package, use the normalized package name instead to disambiguate, e.g., `uv tool run --from script-py other-script.py`
|
||||
");
|
||||
}
|
||||
|
||||
/// Test windows runnable types, namely console scripts and legacy setuptools scripts.
|
||||
/// Console Scripts <https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#console-scripts>
|
||||
/// Legacy Scripts <https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#scripts>.
|
||||
///
|
||||
/// This tests for uv tool run of windows runnable types defined by [`WindowsRunnable`].
|
||||
#[cfg(windows)]
|
||||
#[test]
|
||||
fn tool_run_windows_runnable_types() -> anyhow::Result<()> {
|
||||
let context = TestContext::new("3.12").with_filtered_counts();
|
||||
let tool_dir = context.temp_dir.child("tools");
|
||||
let bin_dir = context.temp_dir.child("bin");
|
||||
|
||||
let foo_dir = context.temp_dir.child("foo");
|
||||
let foo_pyproject_toml = foo_dir.child("pyproject.toml");
|
||||
|
||||
// Use `script-files` which enables legacy scripts packaging.
|
||||
foo_pyproject_toml.write_str(indoc! { r#"
|
||||
[project]
|
||||
name = "foo"
|
||||
version = "1.0.0"
|
||||
requires-python = ">=3.8"
|
||||
dependencies = []
|
||||
|
||||
[project.scripts]
|
||||
custom_pydoc = "foo.main:run"
|
||||
|
||||
[tool.setuptools]
|
||||
script-files = [
|
||||
"misc/custom_pydoc.bat",
|
||||
"misc/custom_pydoc.cmd",
|
||||
"misc/custom_pydoc.ps1"
|
||||
]
|
||||
|
||||
[build-system]
|
||||
requires = ["setuptools>=42"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
"#
|
||||
})?;
|
||||
|
||||
// Create the legacy scripts
|
||||
let custom_pydoc_bat = foo_dir.child("misc").child("custom_pydoc.bat");
|
||||
let custom_pydoc_cmd = foo_dir.child("misc").child("custom_pydoc.cmd");
|
||||
let custom_pydoc_ps1 = foo_dir.child("misc").child("custom_pydoc.ps1");
|
||||
|
||||
custom_pydoc_bat.write_str("python.exe -m pydoc %*")?;
|
||||
custom_pydoc_cmd.write_str("python.exe -m pydoc %*")?;
|
||||
custom_pydoc_ps1.write_str("python.exe -m pydoc $args")?;
|
||||
|
||||
// Create the foo module
|
||||
let foo_project_src = foo_dir.child("src");
|
||||
let foo_module = foo_project_src.child("foo");
|
||||
let foo_main_py = foo_module.child("main.py");
|
||||
foo_main_py.write_str(indoc! { r#"
|
||||
import pydoc, sys
|
||||
|
||||
def run():
|
||||
sys.argv[0] = "pydoc"
|
||||
pydoc.cli()
|
||||
|
||||
__name__ == "__main__" and run()
|
||||
"#
|
||||
})?;
|
||||
|
||||
// Install `foo` tool.
|
||||
context
|
||||
.tool_install()
|
||||
.arg(foo_dir.as_os_str())
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str())
|
||||
.assert()
|
||||
.success();
|
||||
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("does_not_exist")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###"
|
||||
success: false
|
||||
exit_code: 1
|
||||
----- stdout -----
|
||||
The executable `does_not_exist` was not found.
|
||||
The following executables are provided by `foo`:
|
||||
- custom_pydoc.exe
|
||||
- custom_pydoc.bat
|
||||
- custom_pydoc.cmd
|
||||
- custom_pydoc.ps1
|
||||
Consider using `uv tool run --from foo <EXECUTABLE_NAME>` instead.
|
||||
|
||||
----- stderr -----
|
||||
warning: An executable named `does_not_exist` is not provided by package `foo`.
|
||||
"###);
|
||||
|
||||
// Test with explicit .bat extension
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("custom_pydoc.bat")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
pydoc - the Python documentation tool
|
||||
|
||||
pydoc <name> ...
|
||||
Show text documentation on something. <name> may be the name of a
|
||||
Python keyword, topic, function, module, or package, or a dotted
|
||||
reference to a class or function within a module or module in a
|
||||
package. If <name> contains a '\', it is used as the path to a
|
||||
Python source file to document. If name is 'keywords', 'topics',
|
||||
or 'modules', a listing of these things is displayed.
|
||||
|
||||
pydoc -k <keyword>
|
||||
Search for a keyword in the synopsis lines of all available modules.
|
||||
|
||||
pydoc -n <hostname>
|
||||
Start an HTTP server with the given hostname (default: localhost).
|
||||
|
||||
pydoc -p <port>
|
||||
Start an HTTP server on the given port on the local machine. Port
|
||||
number 0 can be used to get an arbitrary unused port.
|
||||
|
||||
pydoc -b
|
||||
Start an HTTP server on an arbitrary unused port and open a web browser
|
||||
to interactively browse documentation. This option can be used in
|
||||
combination with -n and/or -p.
|
||||
|
||||
pydoc -w <name> ...
|
||||
Write out the HTML documentation for a module to a file in the current
|
||||
directory. If <name> contains a '\', it is treated as a filename; if
|
||||
it names a directory, documentation is written for all the contents.
|
||||
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with explicit .cmd extension
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("custom_pydoc.cmd")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
pydoc - the Python documentation tool
|
||||
|
||||
pydoc <name> ...
|
||||
Show text documentation on something. <name> may be the name of a
|
||||
Python keyword, topic, function, module, or package, or a dotted
|
||||
reference to a class or function within a module or module in a
|
||||
package. If <name> contains a '\', it is used as the path to a
|
||||
Python source file to document. If name is 'keywords', 'topics',
|
||||
or 'modules', a listing of these things is displayed.
|
||||
|
||||
pydoc -k <keyword>
|
||||
Search for a keyword in the synopsis lines of all available modules.
|
||||
|
||||
pydoc -n <hostname>
|
||||
Start an HTTP server with the given hostname (default: localhost).
|
||||
|
||||
pydoc -p <port>
|
||||
Start an HTTP server on the given port on the local machine. Port
|
||||
number 0 can be used to get an arbitrary unused port.
|
||||
|
||||
pydoc -b
|
||||
Start an HTTP server on an arbitrary unused port and open a web browser
|
||||
to interactively browse documentation. This option can be used in
|
||||
combination with -n and/or -p.
|
||||
|
||||
pydoc -w <name> ...
|
||||
Write out the HTML documentation for a module to a file in the current
|
||||
directory. If <name> contains a '\', it is treated as a filename; if
|
||||
it names a directory, documentation is written for all the contents.
|
||||
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with explicit .ps1 extension
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("custom_pydoc.ps1")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
pydoc - the Python documentation tool
|
||||
|
||||
pydoc <name> ...
|
||||
Show text documentation on something. <name> may be the name of a
|
||||
Python keyword, topic, function, module, or package, or a dotted
|
||||
reference to a class or function within a module or module in a
|
||||
package. If <name> contains a '\', it is used as the path to a
|
||||
Python source file to document. If name is 'keywords', 'topics',
|
||||
or 'modules', a listing of these things is displayed.
|
||||
|
||||
pydoc -k <keyword>
|
||||
Search for a keyword in the synopsis lines of all available modules.
|
||||
|
||||
pydoc -n <hostname>
|
||||
Start an HTTP server with the given hostname (default: localhost).
|
||||
|
||||
pydoc -p <port>
|
||||
Start an HTTP server on the given port on the local machine. Port
|
||||
number 0 can be used to get an arbitrary unused port.
|
||||
|
||||
pydoc -b
|
||||
Start an HTTP server on an arbitrary unused port and open a web browser
|
||||
to interactively browse documentation. This option can be used in
|
||||
combination with -n and/or -p.
|
||||
|
||||
pydoc -w <name> ...
|
||||
Write out the HTML documentation for a module to a file in the current
|
||||
directory. If <name> contains a '\', it is treated as a filename; if
|
||||
it names a directory, documentation is written for all the contents.
|
||||
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test with explicit .exe extension
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("custom_pydoc")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
pydoc - the Python documentation tool
|
||||
|
||||
pydoc <name> ...
|
||||
Show text documentation on something. <name> may be the name of a
|
||||
Python keyword, topic, function, module, or package, or a dotted
|
||||
reference to a class or function within a module or module in a
|
||||
package. If <name> contains a '\', it is used as the path to a
|
||||
Python source file to document. If name is 'keywords', 'topics',
|
||||
or 'modules', a listing of these things is displayed.
|
||||
|
||||
pydoc -k <keyword>
|
||||
Search for a keyword in the synopsis lines of all available modules.
|
||||
|
||||
pydoc -n <hostname>
|
||||
Start an HTTP server with the given hostname (default: localhost).
|
||||
|
||||
pydoc -p <port>
|
||||
Start an HTTP server on the given port on the local machine. Port
|
||||
number 0 can be used to get an arbitrary unused port.
|
||||
|
||||
pydoc -b
|
||||
Start an HTTP server on an arbitrary unused port and open a web browser
|
||||
to interactively browse documentation. This option can be used in
|
||||
combination with -n and/or -p.
|
||||
|
||||
pydoc -w <name> ...
|
||||
Write out the HTML documentation for a module to a file in the current
|
||||
directory. If <name> contains a '\', it is treated as a filename; if
|
||||
it names a directory, documentation is written for all the contents.
|
||||
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
// Test without explicit extension (.exe should be used)
|
||||
uv_snapshot!(context.filters(), context.tool_run()
|
||||
.arg("--from")
|
||||
.arg("foo")
|
||||
.arg("custom_pydoc")
|
||||
.env(EnvVars::UV_TOOL_DIR, tool_dir.as_os_str())
|
||||
.env(EnvVars::XDG_BIN_HOME, bin_dir.as_os_str())
|
||||
.env(EnvVars::PATH, bin_dir.as_os_str()), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
pydoc - the Python documentation tool
|
||||
|
||||
pydoc <name> ...
|
||||
Show text documentation on something. <name> may be the name of a
|
||||
Python keyword, topic, function, module, or package, or a dotted
|
||||
reference to a class or function within a module or module in a
|
||||
package. If <name> contains a '\', it is used as the path to a
|
||||
Python source file to document. If name is 'keywords', 'topics',
|
||||
or 'modules', a listing of these things is displayed.
|
||||
|
||||
pydoc -k <keyword>
|
||||
Search for a keyword in the synopsis lines of all available modules.
|
||||
|
||||
pydoc -n <hostname>
|
||||
Start an HTTP server with the given hostname (default: localhost).
|
||||
|
||||
pydoc -p <port>
|
||||
Start an HTTP server on the given port on the local machine. Port
|
||||
number 0 can be used to get an arbitrary unused port.
|
||||
|
||||
pydoc -b
|
||||
Start an HTTP server on an arbitrary unused port and open a web browser
|
||||
to interactively browse documentation. This option can be used in
|
||||
combination with -n and/or -p.
|
||||
|
||||
pydoc -w <name> ...
|
||||
Write out the HTML documentation for a module to a file in the current
|
||||
directory. If <name> contains a '\', it is treated as a filename; if
|
||||
it names a directory, documentation is written for all the contents.
|
||||
|
||||
|
||||
----- stderr -----
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,27 @@ print([(k, v["title"]) for k, v in data.items()][:10])
|
|||
The invocation `uv run example.py` would run _isolated_ from the project with only the given
|
||||
dependencies listed.
|
||||
|
||||
## Legacy Windows Scripts
|
||||
|
||||
Support is provided for
|
||||
[legacy setuptools scripts](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#scripts).
|
||||
These types of scripts are additional files installed by setuptools in `.venv\Scripts`.
|
||||
|
||||
Currently only legacy scripts with the `.ps1`, `.cmd`, and `.bat` extensions are supported.
|
||||
|
||||
For example, below is an example running a Command Prompt script.
|
||||
|
||||
```console
|
||||
$ uv run --with nuitka==2.6.7 -- nuitka.cmd --version
|
||||
```
|
||||
|
||||
In addition, you don't need to specify the extension. `uv` will automatically look for files ending
|
||||
in `.ps1`, `.cmd`, and `.bat` in that order of execution on your behalf.
|
||||
|
||||
```console
|
||||
$ uv run --with nuitka==2.6.7 -- nuitka --version
|
||||
```
|
||||
|
||||
## Signal handling
|
||||
|
||||
uv does not cede control of the process to the spawned command in order to provide better error
|
||||
|
|
|
|||
|
|
@ -264,6 +264,27 @@ $ uv tool upgrade --python 3.10 ruff
|
|||
For more details on requesting Python versions, see the
|
||||
[Python version](../concepts/python-versions.md#requesting-a-version) concept page..
|
||||
|
||||
## Legacy Windows Scripts
|
||||
|
||||
Tools also support running
|
||||
[legacy setuptools scripts](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#scripts).
|
||||
These scripts are available via `$(uv tool dir)\<tool-name>\Scripts` when installed.
|
||||
|
||||
Currently only legacy scripts with the `.ps1`, `.cmd`, and `.bat` extensions are supported.
|
||||
|
||||
For example, below is an example running a Command Prompt script.
|
||||
|
||||
```console
|
||||
$ uv tool run --from nuitka==2.6.7 nuitka.cmd --version
|
||||
```
|
||||
|
||||
In addition, you don't need to specify the extension. `uvx` will automatically look for files ending
|
||||
in `.ps1`, `.cmd`, and `.bat` in that order of execution on your behalf.
|
||||
|
||||
```console
|
||||
$ uv tool run --from nuitka==2.6.7 nuitka --version
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
To learn more about managing tools with uv, see the [Tools concept](../concepts/tools.md) page and
|
||||
|
|
|
|||
Loading…
Reference in New Issue