Discover registry PEP 514 Pythons cross 32/64-bit (#11801)

Fixes #11217

By default, a 64-bit uv does not see a 32-bit global (HKLM) installation
of Python in the registry
(https://github.com/astral-sh/uv/issues/11217). To work around this, we
manually request both 32-bit and 64-bit access using registry access
flags (https://peps.python.org/pep-0514/#sample-code). The flags have no
effect on 32-bit (https://stackoverflow.com/a/12796797/3549270).

This effect is that there is an asymmetry between discovery modes: For
the registry-based discovery using PEP 514, we discover both 32-bit and
64-bit Pythons, while for managed installations, we are stricter and
only discover those matching in bit-ness.

I tested this manually with an additional 32-bit installation of CPython
on a 64-bit machine and windows with 32-bit and 64-bit (x86_64 and i686)
builds of uv.
This commit is contained in:
konsti 2025-03-03 15:46:00 +01:00 committed by GitHub
parent 83f1b8b0f1
commit ceffd7ff80
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 4 deletions

View file

@ -14,6 +14,7 @@ use uv_warnings::{warn_user, warn_user_once};
use windows_registry::{Key, Value, CURRENT_USER, HSTRING, LOCAL_MACHINE};
use windows_result::HRESULT;
use windows_sys::Win32::Foundation::ERROR_FILE_NOT_FOUND;
use windows_sys::Win32::System::Registry::{KEY_WOW64_32KEY, KEY_WOW64_64KEY};
/// Code returned when the registry key doesn't exist.
const ERROR_NOT_FOUND: HRESULT = HRESULT::from_win32(ERROR_FILE_NOT_FOUND);
@ -32,9 +33,22 @@ pub(crate) struct WindowsPython {
/// Find all Pythons registered in the Windows registry following PEP 514.
pub(crate) fn registry_pythons() -> Result<Vec<WindowsPython>, windows_result::Error> {
let mut registry_pythons = Vec::new();
// Prefer `HKEY_CURRENT_USER` over `HKEY_LOCAL_MACHINE`
for root_key in [CURRENT_USER, LOCAL_MACHINE] {
let Ok(key_python) = root_key.open(r"Software\Python") else {
// Prefer `HKEY_CURRENT_USER` over `HKEY_LOCAL_MACHINE`.
// By default, a 64-bit program does not see a 32-bit global (HKLM) installation of Python in
// the registry (https://github.com/astral-sh/uv/issues/11217). To work around this, we manually
// request both 32-bit and 64-bit access. The flags have no effect on 32-bit
// (https://stackoverflow.com/a/12796797/3549270).
for (root_key, access_modifier) in [
(CURRENT_USER, None),
(LOCAL_MACHINE, Some(KEY_WOW64_64KEY)),
(LOCAL_MACHINE, Some(KEY_WOW64_32KEY)),
] {
let mut open_options = root_key.options();
open_options.read();
if let Some(access_modifier) = access_modifier {
open_options.access(access_modifier);
}
let Ok(key_python) = open_options.open(r"Software\Python") else {
continue;
};
for company in key_python.keys()? {