Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Install managed Python into the Windows Registry (PEP 514) #10634

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

konstin
Copy link
Member

@konstin konstin commented Jan 15, 2025

Summary

In preview mode on windows, register und un-register the managed python build standalone installations in the Windows registry following PEP 514.

We write the values defined in the PEP plus the download URL and hash. We add an entry when installing a version, remove an entry when uninstalling and removing all values when uninstalling with --all. We update entries only by overwriting existing values, there is no "syncing" involved.

Since they are not official builds, pbs gets a prefix. py -V:Astral/CPython3.13.1 works, py -3.13 doesn't.

$ py --list-paths                                            
 -V:3.12 *        C:\Users\Konsti\AppData\Local\Programs\Python\Python312\python.exe
 -V:3.11.9        C:\Users\Konsti\.pyenv\pyenv-win\versions\3.11.9\python.exe
 -V:3.11          C:\Users\micro\AppData\Local\Programs\Python\Python311\python.exe
 -V:3.8           C:\Users\micro\AppData\Local\Programs\Python\Python38\python.exe
 -V:Astral/CPython3.13.1 C:\Users\Konsti\AppData\Roaming\uv\data\python\cpython-3.13.1-windows-x86_64-none\python.exe

Registry errors are reported but not fatal, except for operations on the company key since it's not bound to any specific python interpreter.

The code uses the official windows_registry crate of the winreg crate.

Best reviewed commit-by-commit.

Test Plan

I manually tested:

  • Installing Python 3.13, finding that Python in the registry viewer and py --list-paths
  • Uninstall Python 3.13 removes the entry from the registry
  • Uninstall with --all removes the entry and unrelated entries from the registry

Since the registry is global, we can't isolate this into integration tests.

@konstin konstin added windows Specific to the Windows platform preview Experimental behavior labels Jan 15, 2025
@konstin konstin requested review from Gankra and zanieb January 15, 2025 13:29
@zanieb zanieb self-assigned this Jan 15, 2025
@Gankra
Copy link
Contributor

Gankra commented Jan 15, 2025

Since the registry is global, we can't isolate this into integration tests.

It's not terribly pleasant but you can do runs-in-serial integration tests that save+restore (or clear) the relevant keys if they're vaguely easy to enumerate (e.g. if they're all under HKCU\Software\Python\Astral).

@zanieb
Copy link
Member

zanieb commented Jan 15, 2025

Need to review still, but could we add coverage to one of our integration tests? Like integration test | free-threaded on windows could assert that we can find it with -py etc.? We could create a dedicated "python install on windows" integration test too.

///
/// If windowed is true, `pythonw.exe` is selected over `python.exe` on windows, with no changes
/// on non-windows.
pub fn executable(&self, windowed: bool) -> PathBuf {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is adding this bool here just for this one use?

    install_path.set_value(
        "WindowedExecutablePath",
        &Value::from(&HSTRING::from(installation.executable(true).as_os_str())),
    )?;

It makes me a little sad to need to pass false everywhere. Unfortunately the logic here is fairly involved... hm.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I bailed on rewriting the entire logic here, not sure either.

@zanieb
Copy link
Member

zanieb commented Jan 15, 2025

Looks good to me! I defer to @Gankra on approval since she's more familiar with Windows.

@zanieb
Copy link
Member

zanieb commented Jan 15, 2025

Just wondering, what's the motivation for

... plus the download URL and hash

Copy link
Contributor

@Gankra Gankra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Biggest concern is the lack of special handling for the "official python install" special cases described in the PEP.

crates/uv-python/src/installation.rs Outdated Show resolved Hide resolved
crates/uv-python/src/lib.rs Show resolved Hide resolved
crates/uv-python/src/managed.rs Show resolved Hide resolved
crates/uv-python/src/windows_registry.rs Show resolved Hide resolved
crates/uv-python/src/windows_registry.rs Show resolved Hide resolved
crates/uv-python/src/windows_registry.rs Outdated Show resolved Hide resolved
crates/uv-python/src/windows_registry.rs Show resolved Hide resolved
crates/uv-python/src/windows_registry.rs Outdated Show resolved Hide resolved
Comment on lines +453 to +458
/// Link the binaries of a managed Python installation to the bin directory.
#[allow(clippy::fn_params_excessive_bools)]
fn create_bin_links(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm going to assume this is a direct cut-paste and not look at it unless you tell me otherwise

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes the first two commits are just moving code around

Comment on lines 342 to 346
if preview.is_enabled() {
uv_python::windows_registry::create_registry_entry(installation, &mut errors)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(i wonder if it would be better to pass in preview and have these functions decide whether they're enabled... nbd tho)

@konstin konstin marked this pull request as draft January 17, 2025 13:02
/// 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();
for root_key in [CURRENT_USER, LOCAL_MACHINE] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I just realized, it's not obvious to me that the current approach actually applies the "CURRENT_USER should shadow LOCAL_MACHINE if they overlap" rule? It seems like the logic here throws out that information completely. (I don't think this has to be a blocker, but it should at least be noted that this is "future work / a looming issue")?

Tools that list every installed environment may choose to include those even where the Company-Tag pairs match. They should ensure users can easily identify whether the registration was per-user or per-machine, and which registration has the higher priority.

Tools that aim to select a single installed environment from all registered environments based on the Company-Tag pair, such as the py.exe launcher, should always select the environment registered in HKEY_CURRENT_USER when than the matching one in HKEY_LOCAL_MACHINE.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way its written sounds like its targeted at a different case than ours: When a user says py -V:Astral/CPython3.13.1, it should use HKEY_CURRENT_USER over HKEY_LOCAL_MACHINE if both have Astral\CPython3.13.1. In uv's discovery, we only support asking of an interpreter kind and a version or version range, and we'll return the first Python we find matching. If a user has the case that they have multiple installations of the same version and they have a specific preference, they can use an absolute path (this should be an edge case). By the order in the list we should still prefer HKEY_CURRENT_USER over HKEY_LOCAL_MACHINE if the version is the same, i added a comment about it.

@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 13:49 — with GitHub Actions Inactive
@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 15:42 — with GitHub Actions Inactive
@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 15:52 — with GitHub Actions Inactive
@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 16:02 — with GitHub Actions Inactive
@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 16:33 — with GitHub Actions Inactive
@konstin konstin temporarily deployed to uv-test-publish January 17, 2025 18:14 — with GitHub Actions Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Experimental behavior windows Specific to the Windows platform
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants