uv-python 0.0.40

This is an internal component crate of uv
Documentation
//! Microsoft Store Pythons don't register themselves in the registry, so we have to look for them
//! in known locations.
//!
//! Effectively a port of <https://github.com/python/cpython/blob/58ce131037ecb34d506a613f21993cde2056f628/PC/launcher2.c#L1744>

use crate::PythonVersion;
use crate::windows_registry::WindowsPython;
use itertools::Either;
use std::env;
use std::path::PathBuf;
use std::str::FromStr;
use tracing::debug;
use uv_static::EnvVars;

#[derive(Debug)]
struct MicrosoftStorePython {
    family_name: &'static str,
    version: &'static str,
}

/// List of known Microsoft Store Pythons.
///
/// Copied from <https://github.com/python/cpython/blob/58ce131037ecb34d506a613f21993cde2056f628/PC/launcher2.c#L1963-L1985>,
/// please update when upstream changes.
const MICROSOFT_STORE_PYTHONS: &[MicrosoftStorePython] = &[
    // Releases made through the Store
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.13_qbz5n2kfra8p0",
        version: "3.13",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.12_qbz5n2kfra8p0",
        version: "3.12",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0",
        version: "3.11",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0",
        version: "3.10",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.9_qbz5n2kfra8p0",
        version: "3.9",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0",
        version: "3.8",
    },
    // Side-loadable releases
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.13_3847v3x7pw1km",
        version: "3.13",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.12_3847v3x7pw1km",
        version: "3.12",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.11_3847v3x7pw1km",
        version: "3.11",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.11_hd69rhyc2wevp",
        version: "3.11",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.10_3847v3x7pw1km",
        version: "3.10",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.10_hd69rhyc2wevp",
        version: "3.10",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.9_3847v3x7pw1km",
        version: "3.9",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.9_hd69rhyc2wevp",
        version: "3.9",
    },
    MicrosoftStorePython {
        family_name: "PythonSoftwareFoundation.Python.3.8_hd69rhyc2wevp",
        version: "3.8",
    },
];

/// Microsoft Store Pythons don't register themselves in the registry, so we have to look for them
/// in known locations.
///
/// Effectively a port of <https://github.com/python/cpython/blob/58ce131037ecb34d506a613f21993cde2056f628/PC/launcher2.c#L1744>
pub(crate) fn find_microsoft_store_pythons() -> impl Iterator<Item = WindowsPython> {
    let Ok(local_app_data) = env::var(EnvVars::LOCALAPPDATA) else {
        debug!("`LOCALAPPDATA` not set, ignoring Microsoft store Pythons");
        return Either::Left(std::iter::empty());
    };

    let windows_apps = PathBuf::from(local_app_data)
        .join("Microsoft")
        .join("WindowsApps");

    Either::Right(
        MICROSOFT_STORE_PYTHONS
            .iter()
            .map(move |store_python| {
                let path = windows_apps
                    .join(store_python.family_name)
                    .join("python.exe");
                WindowsPython {
                    path,
                    // All versions are constants, we know they are valid.
                    version: Some(PythonVersion::from_str(store_python.version).unwrap()),
                }
            })
            .filter(|windows_python| windows_python.path.is_file()),
    )
}