mise 的幺蛾子还在继续飞
前文《mise 升级又出幺蛾子》中记录了 mise 在 Windows 平台上安装 PHP 的坑,这次又发现了一个 mise 在 Windows 上安装 Python 的坑。主要问题是 mise 内置的 Python 插件在 Windows 平台上返回了错误的安装路径。
发现问题
我当前的 Windows 系统同时安装了 mise 和 uv。前者负责管理系统的开发工具,后者负责管理 Python 项目以及安装全局 Python 工具。直到最近用 mise 将 Python 版本从 3.14.7 升级到 3.14.8 后,发现 uv tool update 更新失败,提示 Python 没有正确安装。
直接原因是,mise 升级 Python 后,之前的 Python 3.14.7 目录已被删除,而那些由 uv 安装的 Python 工具,其配置文件 pyvenv.cfg 中的 home 都指向了已删除的 Python 安装路径。也就是说,Python 升级前,执行 which python 命令,显示的路径是 D:\Data\mise\installs\python\3.14.7\python.exe,而升级后变成了 D:\Data\mise\installs\python\3.14.8\python.exe。
原因分析
uv 安装的 Python 工具,其虚拟环境所依赖的 Python 安装路径是在创建环境时确定的,不会随 mise 升级 Python 而自动更新。照理说,系统全局的 Python 路径应该是固定的,并且通过符号连接指向最终版本的可执行文件。事实上 mise 安装的 Python 也的确提供了符号链接:
目录:D:\Data\mise\installs\python
Mode LastWriteTime Length Name
---- ------------- ------ ----
l---- 2026/10/9 16:28 3 D:\Data\mise\installs\python\3.14.8
l---- 2026/10/9 16:28 3.14 D:\Data\mise\installs\python\3.14.8
d---- 2026/10/9 16:28 3.14.8
l---- 2026/10/13 9:54 global D:\Data\mise\installs\python\3.14.8
l---- 2026/10/9 16:28 latest D:\Data\mise\installs\python\3.14.8
-a--- 2026/10/9 16:28 61 .mise.backend.toml但是由 mise activate pwsh 导入的环境变量里,却是一个带版本号的路径。通过 mise bin-paths python 命令查看最终导入的 Python 路径如下:
D:\Data\mise\installs\python\3.14.8
D:\Data\mise\installs\python\3.14.8\Scripts而不是希望的固定路径。比如:
D:\Data\mise\installs\python\global
D:\Data\mise\installs\python\global\Scripts甚至也不是不带小版本号的路径。比如:
D:\Data\mise\installs\python\3.14
D:\Data\mise\installs\python\3.14\Scripts翻看了 mise 的源代码,发现这竟然还是一个 Windows 特供版 BUG。
mise 解析 bin paths 的默认逻辑由 mod.rs 的 list_bin_paths() 函数实现:
rustasync fn list_bin_paths(
&self,
_config: &Arc<Config>,
tv: &ToolVersion,
) -> Result<Vec<PathBuf>> {
match tv.request {
ToolRequest::System { .. } => Ok(vec![]),
_ => Ok(vec![tv.runtime_path().join("bin")]),
}
}可 mise 内置的 Python 插件却特地为 Windows 提供了一个专属的版本:
rust#[cfg(windows)]
async fn list_bin_paths(
&self,
_config: &Arc<Config>,
tv: &ToolVersion,
) -> eyre::Result<Vec<PathBuf>> {
// The install root holds python.exe/python3.exe and the synthesized
// pip wrappers; Scripts is where pip installs console-script
// launchers (black.exe, ...). Root stays first so interpreter/pip
// resolution is stable. Scripts is returned unconditionally per the
// trait contract (candidates, not existing dirs — see
// Backend::list_bin_paths docs); it may not exist until the first
// `pip install`.
Ok(vec![tv.install_path(), tv.install_path().join("Scripts")])
}前者返回的是符号链接路径,而后者返回的是符号链接指向的路径。这就是引发问题的根源。
解决方案
我不清楚 mise 这样做的理由是什么(也许有什么不得已的苦衷?),也懒得给项目提 PR。不过这个 BUG 倒是可以简单用 PowerShell 脚本修复。
在 PowerShell 命令行下执行 notepad $PROFILE 打开配置文件,在 Invoke-Expression (& { mise activate pwsh | Out-String }) 后面添加如下内容:
powershell$env:PATH = ($env:PATH -split ';' | ForEach-Object {
$_ -replace '(?i)^(D:\\Data\\mise\\installs\\python\\)\d+\.\d+\.\d+(\\Scripts)?$', '${1}global${2}'
}) -join ';'另外我发现,mise 添加的 PATH 路径 D:\Data\mise\shims 中其实有各可执行文件的 shims,也就是说不用单独添加 Python 路径也是可以的。我不清楚 mise 这样设计的理由是什么,想必也有什么不得已的苦衷吧。