Skip to content

Commit 2ca39f1

Browse files
Skip root when assessing prefix viability (#9823)
## Summary In CPython, it appears that `/` is not considered as a valid path in `search_up`: ```c static PyObject * getpath_dirname(PyObject *Py_UNUSED(self), PyObject *args) { PyObject *path; if (!PyArg_ParseTuple(args, "U", &path)) { return NULL; } Py_ssize_t end = PyUnicode_GET_LENGTH(path); Py_ssize_t pos = PyUnicode_FindChar(path, SEP, 0, end, -1); if (pos < 0) { return PyUnicode_FromStringAndSize(NULL, 0); } return PyUnicode_Substring(path, 0, pos); } ``` ```python def search_up(prefix, *landmarks, test=isfile): while prefix: if any(test(joinpath(prefix, f)) for f in landmarks): return prefix prefix = dirname(prefix) ``` Closes #9818.
1 parent a41ef21 commit 2ca39f1

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

crates/uv-virtualenv/src/virtualenv.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,12 @@ fn copy_launcher_windows(
655655
///
656656
/// See: <https://github.com/python/cpython/blob/a03efb533a58fd13fb0cc7f4a5c02c8406a407bd/Modules/getpath.py#L591-L594>
657657
fn find_base_python(executable: &Path, major: u8, minor: u8) -> Result<PathBuf, io::Error> {
658+
/// Returns `true` if `path` is the root directory.
659+
fn is_root(path: &Path) -> bool {
660+
let mut components = path.components();
661+
components.next() == Some(std::path::Component::RootDir) && components.next().is_none()
662+
}
663+
658664
/// Determining whether `dir` is a valid Python prefix by searching for a "landmark".
659665
///
660666
/// See: <https://github.com/python/cpython/blob/a03efb533a58fd13fb0cc7f4a5c02c8406a407bd/Modules/getpath.py#L183>
@@ -678,7 +684,7 @@ fn find_base_python(executable: &Path, major: u8, minor: u8) -> Result<PathBuf,
678684
);
679685

680686
// Determine whether this executable will produce a valid `home` for a virtual environment.
681-
for prefix in executable.ancestors() {
687+
for prefix in executable.ancestors().take_while(|path| !is_root(path)) {
682688
if is_prefix(prefix, major, minor) {
683689
return Ok(executable.into_owned());
684690
}

0 commit comments

Comments
 (0)