mirror of https://github.com/astral-sh/uv
Enable `freeze` and `list` to introspect non-virtualenv Pythons (#2033)
## Summary Now that we have the ability to introspect the installed packages for arbitrary Pythons, we can allow `pip freeze` and `pip list` to fall back to the "default" Python, if no virtualenv is present. Closes https://github.com/astral-sh/uv/issues/2005.
This commit is contained in:
parent
23afa09fae
commit
02703281f0
|
|
@ -68,7 +68,7 @@ pub fn find_requested_python(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pick a sensible default for the python a user wants when they didn't specify a version.
|
/// Pick a sensible default for the Python a user wants when they didn't specify a version.
|
||||||
///
|
///
|
||||||
/// We prefer the test overwrite `UV_TEST_PYTHON_PATH` if it is set, otherwise `python3`/`python` or
|
/// We prefer the test overwrite `UV_TEST_PYTHON_PATH` if it is set, otherwise `python3`/`python` or
|
||||||
/// `python.exe` respectively.
|
/// `python.exe` respectively.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use uv_fs::{LockedFile, Normalized};
|
||||||
|
|
||||||
use crate::cfg::PyVenvConfiguration;
|
use crate::cfg::PyVenvConfiguration;
|
||||||
use crate::python_platform::PythonPlatform;
|
use crate::python_platform::PythonPlatform;
|
||||||
use crate::{find_requested_python, Error, Interpreter};
|
use crate::{find_default_python, find_requested_python, Error, Interpreter};
|
||||||
|
|
||||||
/// A Python executable and its associated platform markers.
|
/// A Python executable and its associated platform markers.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -65,6 +65,15 @@ impl Virtualenv {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a [`Virtualenv`] for the default Python interpreter.
|
||||||
|
pub fn from_default_python(platform: &Platform, cache: &Cache) -> Result<Self, Error> {
|
||||||
|
let interpreter = find_default_python(platform, cache)?;
|
||||||
|
Ok(Self {
|
||||||
|
root: interpreter.base_prefix().to_path_buf(),
|
||||||
|
interpreter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the location of the Python interpreter.
|
/// Returns the location of the Python interpreter.
|
||||||
pub fn root(&self) -> &Path {
|
pub fn root(&self) -> &Path {
|
||||||
&self.root
|
&self.root
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ use crate::printer::Printer;
|
||||||
|
|
||||||
/// Clear the cache.
|
/// Clear the cache.
|
||||||
pub(crate) fn cache_clean(
|
pub(crate) fn cache_clean(
|
||||||
cache: &Cache,
|
|
||||||
packages: &[PackageName],
|
packages: &[PackageName],
|
||||||
|
cache: &Cache,
|
||||||
mut printer: Printer,
|
mut printer: Printer,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
if !cache.root().exists() {
|
if !cache.root().exists() {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,25 @@ use crate::commands::ExitStatus;
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
|
|
||||||
/// Enumerate the installed packages in the current environment.
|
/// Enumerate the installed packages in the current environment.
|
||||||
pub(crate) fn pip_freeze(cache: &Cache, strict: bool, mut printer: Printer) -> Result<ExitStatus> {
|
pub(crate) fn pip_freeze(
|
||||||
|
strict: bool,
|
||||||
|
python: Option<&str>,
|
||||||
|
cache: &Cache,
|
||||||
|
mut printer: Printer,
|
||||||
|
) -> Result<ExitStatus> {
|
||||||
// Detect the current Python interpreter.
|
// Detect the current Python interpreter.
|
||||||
let platform = Platform::current()?;
|
let platform = Platform::current()?;
|
||||||
let venv = Virtualenv::from_env(platform, cache)?;
|
let venv = if let Some(python) = python {
|
||||||
|
Virtualenv::from_requested_python(python, &platform, cache)?
|
||||||
|
} else {
|
||||||
|
match Virtualenv::from_env(platform.clone(), cache) {
|
||||||
|
Ok(venv) => venv,
|
||||||
|
Err(uv_interpreter::Error::VenvNotFound) => {
|
||||||
|
Virtualenv::from_default_python(&platform, cache)?
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Using Python {} environment at {}",
|
"Using Python {} environment at {}",
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,27 @@ use crate::printer::Printer;
|
||||||
|
|
||||||
/// Enumerate the installed packages in the current environment.
|
/// Enumerate the installed packages in the current environment.
|
||||||
pub(crate) fn pip_list(
|
pub(crate) fn pip_list(
|
||||||
cache: &Cache,
|
|
||||||
strict: bool,
|
strict: bool,
|
||||||
editable: bool,
|
editable: bool,
|
||||||
exclude_editable: bool,
|
exclude_editable: bool,
|
||||||
exclude: &[PackageName],
|
exclude: &[PackageName],
|
||||||
|
python: Option<&str>,
|
||||||
|
cache: &Cache,
|
||||||
mut printer: Printer,
|
mut printer: Printer,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
// Detect the current Python interpreter.
|
// Detect the current Python interpreter.
|
||||||
let platform = Platform::current()?;
|
let platform = Platform::current()?;
|
||||||
let venv = Virtualenv::from_env(platform, cache)?;
|
let venv = if let Some(python) = python {
|
||||||
|
Virtualenv::from_requested_python(python, &platform, cache)?
|
||||||
|
} else {
|
||||||
|
match Virtualenv::from_env(platform.clone(), cache) {
|
||||||
|
Ok(venv) => venv,
|
||||||
|
Err(uv_interpreter::Error::VenvNotFound) => {
|
||||||
|
Virtualenv::from_default_python(&platform, cache)?
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"Using Python {} environment at {}",
|
"Using Python {} environment at {}",
|
||||||
|
|
|
||||||
|
|
@ -730,6 +730,20 @@ struct PipFreezeArgs {
|
||||||
/// issues.
|
/// issues.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
strict: bool,
|
strict: bool,
|
||||||
|
|
||||||
|
/// The Python interpreter for which packages should be listed.
|
||||||
|
///
|
||||||
|
/// By default, `uv` lists packages in the currently activated virtual environment, or a virtual
|
||||||
|
/// environment (`.venv`) located in the current working directory or any parent directory,
|
||||||
|
/// falling back to the system Python if no virtual environment is found.
|
||||||
|
///
|
||||||
|
/// Supported formats:
|
||||||
|
/// - `3.10` looks for an installed Python 3.10 using `py --list-paths` on Windows, or
|
||||||
|
/// `python3.10` on Linux and macOS. (Specifying a patch version is not supported.)
|
||||||
|
/// - `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.
|
||||||
|
#[clap(long, short, verbatim_doc_comment)]
|
||||||
|
python: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -751,6 +765,20 @@ struct PipListArgs {
|
||||||
/// Exclude the specified package(s) from the output.
|
/// Exclude the specified package(s) from the output.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
r#exclude: Vec<PackageName>,
|
r#exclude: Vec<PackageName>,
|
||||||
|
|
||||||
|
/// The Python interpreter for which packages should be listed.
|
||||||
|
///
|
||||||
|
/// By default, `uv` lists packages in the currently activated virtual environment, or a virtual
|
||||||
|
/// environment (`.venv`) located in the current working directory or any parent directory,
|
||||||
|
/// falling back to the system Python if no virtual environment is found.
|
||||||
|
///
|
||||||
|
/// Supported formats:
|
||||||
|
/// - `3.10` looks for an installed Python 3.10 using `py --list-paths` on Windows, or
|
||||||
|
/// `python3.10` on Linux and macOS. (Specifying a patch version is not supported.)
|
||||||
|
/// - `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.
|
||||||
|
#[clap(long, short, verbatim_doc_comment)]
|
||||||
|
python: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Args)]
|
#[derive(Args)]
|
||||||
|
|
@ -1160,21 +1188,22 @@ async fn run() -> Result<ExitStatus> {
|
||||||
}
|
}
|
||||||
Commands::Pip(PipNamespace {
|
Commands::Pip(PipNamespace {
|
||||||
command: PipCommand::Freeze(args),
|
command: PipCommand::Freeze(args),
|
||||||
}) => commands::pip_freeze(&cache, args.strict, printer),
|
}) => commands::pip_freeze(args.strict, args.python.as_deref(), &cache, printer),
|
||||||
Commands::Pip(PipNamespace {
|
Commands::Pip(PipNamespace {
|
||||||
command: PipCommand::List(args),
|
command: PipCommand::List(args),
|
||||||
}) => commands::pip_list(
|
}) => commands::pip_list(
|
||||||
&cache,
|
|
||||||
args.strict,
|
args.strict,
|
||||||
args.editable,
|
args.editable,
|
||||||
args.exclude_editable,
|
args.exclude_editable,
|
||||||
&args.exclude,
|
&args.exclude,
|
||||||
|
args.python.as_deref(),
|
||||||
|
&cache,
|
||||||
printer,
|
printer,
|
||||||
),
|
),
|
||||||
Commands::Cache(CacheNamespace {
|
Commands::Cache(CacheNamespace {
|
||||||
command: CacheCommand::Clean(args),
|
command: CacheCommand::Clean(args),
|
||||||
})
|
})
|
||||||
| Commands::Clean(args) => commands::cache_clean(&cache, &args.package, printer),
|
| Commands::Clean(args) => commands::cache_clean(&args.package, &cache, printer),
|
||||||
Commands::Cache(CacheNamespace {
|
Commands::Cache(CacheNamespace {
|
||||||
command: CacheCommand::Dir,
|
command: CacheCommand::Dir,
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue