Skip to content

Commit

Permalink
Support unnamed requirements directly in pip uninstall
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Mar 20, 2024
1 parent 3dedfbf commit 6965eaf
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 37 deletions.
7 changes: 5 additions & 2 deletions crates/uv-installer/src/site_packages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ impl<'a> SitePackages<'a> {
.push(idx);

// Index the distribution by URL.
if let Some(url) = dist_info.as_editable() {
by_url.entry(url.clone()).or_insert_with(Vec::new).push(idx);
if let InstalledDist::Url(dist) = &dist_info {
by_url
.entry(dist.url.clone())
.or_insert_with(Vec::new)
.push(idx);
}

// Add the distribution to the database.
Expand Down
58 changes: 28 additions & 30 deletions crates/uv/src/commands/pip_uninstall.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::fmt::Write;

use anyhow::Result;
use itertools::{Either, Itertools};
use owo_colors::OwoColorize;
use tracing::debug;

use distribution_types::{InstalledMetadata, Name};
use pep508_rs::{Requirement, RequirementsTxtRequirement, UnnamedRequirement};
use uv_cache::Cache;
use uv_client::Connectivity;
use uv_fs::Simplified;
Expand Down Expand Up @@ -63,27 +65,23 @@ pub(crate) async fn pip_uninstall(
}
}

// Convert from unnamed to named requirements.
let NamedRequirements {
project: _,
requirements,
constraints: _,
overrides: _,
editables,
index_url: _,
extra_index_urls: _,
no_index: _,
find_links: _,
} = NamedRequirements::from_spec(spec)?;

let _lock = venv.lock()?;

// Index the current `site-packages` directory.
let site_packages = uv_installer::SitePackages::from_executable(&venv)?;

// Sort and deduplicate the packages, which are keyed by name.
let packages = {
let mut packages = requirements
// Partition the requirements into named and unnamed requirements.
let (named, unnamed): (Vec<Requirement>, Vec<UnnamedRequirement>) = spec
.requirements
.into_iter()
.partition_map(|requirement| match requirement {
RequirementsTxtRequirement::Pep508(requirement) => Either::Left(requirement),
RequirementsTxtRequirement::Unnamed(requirement) => Either::Right(requirement),
});

// Sort and deduplicate the PEP 508 requirements, which are keyed by package name.
let names = {
let mut packages = named
.into_iter()
.map(|requirement| requirement.name)
.collect::<Vec<_>>();
Expand All @@ -92,23 +90,23 @@ pub(crate) async fn pip_uninstall(
packages
};

// Sort and deduplicate the editable packages, which are keyed by URL rather than package name.
let editables = {
let mut editables = editables
.iter()
.map(requirements_txt::EditableRequirement::raw)
// Sort and deduplicate the unnamed requirements, which are keyed by URL rather than package name.
let urls = {
let mut urls = unnamed
.into_iter()
.map(|requirement| requirement.url.to_url())
.collect::<Vec<_>>();
editables.sort_unstable();
editables.dedup();
editables
urls.sort_unstable();
urls.dedup();
urls
};

// Map to the local distributions.
let distributions = {
let mut distributions = Vec::with_capacity(packages.len() + editables.len());
let mut distributions = Vec::with_capacity(names.len() + urls.len());

// Identify all packages that are installed.
for package in &packages {
for package in &names {
let installed = site_packages.get_packages(package);
if installed.is_empty() {
writeln!(
Expand All @@ -123,16 +121,16 @@ pub(crate) async fn pip_uninstall(
}
}

// Identify all editables that are installed.
for editable in &editables {
let installed = site_packages.get_editables(editable);
// Identify all unnamed distributions that are installed.
for url in &urls {
let installed = site_packages.get_urls(url);
if installed.is_empty() {
writeln!(
printer.stderr(),
"{}{} Skipping {} as it is not installed.",
"warning".yellow().bold(),
":".bold(),
editable.as_ref().bold()
url.as_ref().bold()
)?;
} else {
distributions.extend(installed);
Expand Down
5 changes: 0 additions & 5 deletions crates/uv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -960,10 +960,6 @@ struct PipUninstallArgs {
#[clap(long, short, group = "sources")]
requirement: Vec<PathBuf>,

/// Uninstall the editable package based on the provided local file path.
#[clap(long, short, group = "sources")]
editable: Vec<String>,

/// The Python interpreter from which packages should be uninstalled.
///
/// By default, `uv` uninstalls from the virtual environment in the current working directory or
Expand Down Expand Up @@ -1706,7 +1702,6 @@ async fn run() -> Result<ExitStatus> {
.package
.into_iter()
.map(RequirementsSource::from_package)
.chain(args.editable.into_iter().map(RequirementsSource::Editable))
.chain(
args.requirement
.into_iter()
Expand Down

0 comments on commit 6965eaf

Please sign in to comment.