Skip to content

Commit 0fbc8ba

Browse files
committed
Add uv python pin --rm to remove .python-version pins
1 parent efd4652 commit 0fbc8ba

File tree

5 files changed

+84
-0
lines changed

5 files changed

+84
-0
lines changed

crates/uv-cli/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5032,6 +5032,10 @@ pub struct PythonPinArgs {
50325032
/// directory, this version will be used instead.
50335033
#[arg(long)]
50345034
pub global: bool,
5035+
5036+
/// Remove the Python version pin.
5037+
#[arg(long, conflicts_with = "request", conflicts_with = "resolved")]
5038+
pub rm: bool,
50355039
}
50365040

50375041
#[derive(Args)]

crates/uv/src/commands/python/pin.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub(crate) async fn pin(
2727
python_preference: PythonPreference,
2828
no_project: bool,
2929
global: bool,
30+
rm: bool,
3031
cache: &Cache,
3132
printer: Printer,
3233
) -> Result<ExitStatus> {
@@ -56,6 +57,20 @@ pub(crate) async fn pin(
5657
PythonVersionFile::discover(project_dir, &VersionFileDiscoveryOptions::default()).await
5758
};
5859

60+
if rm {
61+
if let Some(file) = version_file? {
62+
fs_err::tokio::remove_file(file.path()).await?;
63+
writeln!(
64+
printer.stdout(),
65+
"Removed Python version file at `{}`",
66+
file.path().user_display()
67+
)?;
68+
return Ok(ExitStatus::Success);
69+
} else {
70+
bail!("No Python version file found");
71+
}
72+
}
73+
5974
let Some(request) = request else {
6075
// Display the current pinned Python version
6176
if let Some(file) = version_file? {

crates/uv/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
14661466
globals.python_preference,
14671467
args.no_project,
14681468
args.global,
1469+
args.rm,
14691470
&cache,
14701471
printer,
14711472
)

crates/uv/src/settings.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,7 @@ pub(crate) struct PythonPinSettings {
10561056
pub(crate) resolved: bool,
10571057
pub(crate) no_project: bool,
10581058
pub(crate) global: bool,
1059+
pub(crate) rm: bool,
10591060
}
10601061

10611062
impl PythonPinSettings {
@@ -1068,13 +1069,15 @@ impl PythonPinSettings {
10681069
resolved,
10691070
no_project,
10701071
global,
1072+
rm,
10711073
} = args;
10721074

10731075
Self {
10741076
request,
10751077
resolved: flag(resolved, no_resolved).unwrap_or(false),
10761078
no_project,
10771079
global,
1080+
rm,
10781081
}
10791082
}
10801083
}

crates/uv/tests/it/python_pin.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::path::PathBuf;
22

33
use crate::common::{TestContext, uv_snapshot};
44
use anyhow::Result;
5+
use assert_cmd::assert::OutputAssertExt;
56
use assert_fs::fixture::{FileWriteStr, PathChild, PathCreateDir};
67
use insta::assert_snapshot;
78
use uv_python::{
@@ -814,3 +815,63 @@ fn python_pin_with_comments() -> Result<()> {
814815

815816
Ok(())
816817
}
818+
819+
#[test]
820+
fn python_pin_rm() {
821+
let context: TestContext = TestContext::new_with_versions(&["3.12"]);
822+
823+
uv_snapshot!(context.filters(), context.python_pin().arg("--rm"), @r"
824+
success: false
825+
exit_code: 2
826+
----- stdout -----
827+
828+
----- stderr -----
829+
error: No Python version file found
830+
");
831+
832+
// Remove the local pin
833+
context.python_pin().arg("3.12").assert().success();
834+
uv_snapshot!(context.filters(), context.python_pin().arg("--rm"), @r"
835+
success: true
836+
exit_code: 0
837+
----- stdout -----
838+
Removed Python version file at `.python-version`
839+
840+
----- stderr -----
841+
");
842+
843+
uv_snapshot!(context.filters(), context.python_pin().arg("--rm").arg("--global"), @r"
844+
success: false
845+
exit_code: 2
846+
----- stdout -----
847+
848+
----- stderr -----
849+
error: No Python version file found
850+
");
851+
852+
// Global does not detect the local pin
853+
context.python_pin().arg("3.12").assert().success();
854+
uv_snapshot!(context.filters(), context.python_pin().arg("--rm").arg("--global"), @r"
855+
success: false
856+
exit_code: 2
857+
----- stdout -----
858+
859+
----- stderr -----
860+
error: No Python version file found
861+
");
862+
863+
context
864+
.python_pin()
865+
.arg("3.12")
866+
.arg("--global")
867+
.assert()
868+
.success();
869+
uv_snapshot!(context.filters(), context.python_pin().arg("--rm").arg("--global"), @r"
870+
success: true
871+
exit_code: 0
872+
----- stdout -----
873+
Removed Python version file at `[UV_USER_CONFIG_DIR]/.python-version`
874+
875+
----- stderr -----
876+
");
877+
}

0 commit comments

Comments
 (0)