mirror of https://github.com/astral-sh/uv
Add `--python` support to `uv run` (#3189)
This commit is contained in:
parent
005b76770e
commit
eb27d742b9
|
|
@ -1706,6 +1706,20 @@ pub(crate) struct RunArgs {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub(crate) with: Vec<String>,
|
pub(crate) with: Vec<String>,
|
||||||
|
|
||||||
|
/// The Python interpreter to use to build the run environment.
|
||||||
|
///
|
||||||
|
/// By default, `uv` uses the virtual environment in the current working directory or any parent
|
||||||
|
/// directory, falling back to searching for a Python executable in `PATH`. The `--python`
|
||||||
|
/// option allows you to specify a different interpreter.
|
||||||
|
///
|
||||||
|
/// Supported formats:
|
||||||
|
/// - `3.10` looks for an installed Python 3.10 using `py --list-paths` on Windows, or
|
||||||
|
/// `python3.10` on Linux and macOS.
|
||||||
|
/// - `python3.10` or `python.exe` looks for a binary with the given name in `PATH`.
|
||||||
|
/// - `/home/ferris/.local/bin/python3.10` uses the exact Python at the given path.
|
||||||
|
#[arg(long, short, verbatim_doc_comment, group = "discovery")]
|
||||||
|
pub(crate) python: Option<String>,
|
||||||
|
|
||||||
/// Run without the current workspace installed.
|
/// Run without the current workspace installed.
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
pub(crate) no_workspace: bool,
|
pub(crate) no_workspace: bool,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub(crate) async fn run(
|
||||||
target: Option<String>,
|
target: Option<String>,
|
||||||
mut args: Vec<OsString>,
|
mut args: Vec<OsString>,
|
||||||
mut requirements: Vec<RequirementsSource>,
|
mut requirements: Vec<RequirementsSource>,
|
||||||
|
python: Option<String>,
|
||||||
isolated: bool,
|
isolated: bool,
|
||||||
no_workspace: bool,
|
no_workspace: bool,
|
||||||
preview: PreviewMode,
|
preview: PreviewMode,
|
||||||
|
|
@ -86,7 +87,15 @@ pub(crate) async fn run(
|
||||||
// Detect the current Python interpreter.
|
// Detect the current Python interpreter.
|
||||||
// TODO(zanieb): Create ephemeral environments
|
// TODO(zanieb): Create ephemeral environments
|
||||||
// TODO(zanieb): Accept `--python`
|
// TODO(zanieb): Accept `--python`
|
||||||
let run_env = environment_for_run(&requirements, &overrides, isolated, cache, printer).await?;
|
let run_env = environment_for_run(
|
||||||
|
&requirements,
|
||||||
|
&overrides,
|
||||||
|
python.as_deref(),
|
||||||
|
isolated,
|
||||||
|
cache,
|
||||||
|
printer,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
let python_env = run_env.python;
|
let python_env = run_env.python;
|
||||||
|
|
||||||
// Construct the command
|
// Construct the command
|
||||||
|
|
@ -164,6 +173,7 @@ fn find_workspace_requirements() -> Result<Option<Vec<RequirementsSource>>> {
|
||||||
async fn environment_for_run(
|
async fn environment_for_run(
|
||||||
requirements: &[RequirementsSource],
|
requirements: &[RequirementsSource],
|
||||||
overrides: &[RequirementsSource],
|
overrides: &[RequirementsSource],
|
||||||
|
python: Option<&str>,
|
||||||
isolated: bool,
|
isolated: bool,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
|
|
@ -194,8 +204,19 @@ async fn environment_for_run(
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// Determine an interpreter to use
|
||||||
|
let python_env = if let Some(python) = python {
|
||||||
|
PythonEnvironment::from_requested_python(python, cache)?
|
||||||
|
} else {
|
||||||
|
PythonEnvironment::from_default_python(cache)?
|
||||||
|
};
|
||||||
|
|
||||||
// Check if the current environment satisfies the requirements
|
// Check if the current environment satisfies the requirements
|
||||||
if let Some(venv) = current_venv {
|
if let Some(venv) = current_venv {
|
||||||
|
// Ensure it matches the selected interpreter
|
||||||
|
// TODO(zanieb): We should check if a version was requested and see if the environment meets that
|
||||||
|
// too but this can wait until we refactor interpreter discovery
|
||||||
|
if venv.root() == python_env.root() {
|
||||||
// Determine the set of installed packages.
|
// Determine the set of installed packages.
|
||||||
let site_packages = SitePackages::from_executable(&venv)?;
|
let site_packages = SitePackages::from_executable(&venv)?;
|
||||||
|
|
||||||
|
|
@ -203,7 +224,11 @@ async fn environment_for_run(
|
||||||
// enough to let us remove this check. But right now, for large environments, it's an order of
|
// enough to let us remove this check. But right now, for large environments, it's an order of
|
||||||
// magnitude faster to validate the environment than to resolve the requirements.
|
// magnitude faster to validate the environment than to resolve the requirements.
|
||||||
if spec.source_trees.is_empty()
|
if spec.source_trees.is_empty()
|
||||||
&& site_packages.satisfies(&spec.requirements, &spec.editables, &spec.constraints)?
|
&& site_packages.satisfies(
|
||||||
|
&spec.requirements,
|
||||||
|
&spec.editables,
|
||||||
|
&spec.constraints,
|
||||||
|
)?
|
||||||
{
|
{
|
||||||
debug!("Current environment satisfies requirements");
|
debug!("Current environment satisfies requirements");
|
||||||
return Ok(RunEnvironment {
|
return Ok(RunEnvironment {
|
||||||
|
|
@ -212,17 +237,9 @@ async fn environment_for_run(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Otherwise, we need a new environment
|
// Otherwise, we need a new environment
|
||||||
|
|
||||||
// Find an interpreter to use
|
|
||||||
// TODO(zanieb): Populate `python` from the user
|
|
||||||
let python = None;
|
|
||||||
let python_env = if let Some(python) = python {
|
|
||||||
PythonEnvironment::from_requested_python(python, cache)?
|
|
||||||
} else {
|
|
||||||
PythonEnvironment::from_default_python(cache)?
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create a virtual environment
|
// Create a virtual environment
|
||||||
// TODO(zanieb): Move this path derivation elsewhere
|
// TODO(zanieb): Move this path derivation elsewhere
|
||||||
let uv_state_path = std::env::current_dir()?.join(".uv");
|
let uv_state_path = std::env::current_dir()?.join(".uv");
|
||||||
|
|
|
||||||
|
|
@ -507,6 +507,7 @@ async fn run() -> Result<ExitStatus> {
|
||||||
args.target,
|
args.target,
|
||||||
args.args,
|
args.args,
|
||||||
requirements,
|
requirements,
|
||||||
|
args.python,
|
||||||
args.isolated,
|
args.isolated,
|
||||||
args.no_workspace,
|
args.no_workspace,
|
||||||
globals.preview,
|
globals.preview,
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ pub(crate) struct RunSettings {
|
||||||
pub(crate) isolated: bool,
|
pub(crate) isolated: bool,
|
||||||
pub(crate) with: Vec<String>,
|
pub(crate) with: Vec<String>,
|
||||||
pub(crate) no_workspace: bool,
|
pub(crate) no_workspace: bool,
|
||||||
|
pub(crate) python: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunSettings {
|
impl RunSettings {
|
||||||
|
|
@ -100,6 +101,7 @@ impl RunSettings {
|
||||||
isolated,
|
isolated,
|
||||||
with,
|
with,
|
||||||
no_workspace,
|
no_workspace,
|
||||||
|
python,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -109,6 +111,7 @@ impl RunSettings {
|
||||||
isolated,
|
isolated,
|
||||||
with,
|
with,
|
||||||
no_workspace,
|
no_workspace,
|
||||||
|
python,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue