现象:编辑器 / pyright 满屏 reportMissingImports,但 .venv 与 conda 环境里 import numpy, pandas 都正常,pytest 也全过。 根因两层: 1. pyright 没配 venvPath / pythonPath 时会去 PATH 上找 python。本机 PATH 上 唯一的 python 是 agent-tools 的 shim(Codex 运行时,Python 3.14),没有科学栈。 pyright --verbose 显示它选了 3.14.6,Search paths 里一个 Anaconda 路径都没有。 注意持久化的 User/Machine PATH 并没有这一项,是 Codex 进程临时注入的——所以 "我的终端没问题"和"工具有问题"可以同时成立。 2. .venv 是 --system-site-packages 建的,三方包在 D:\anaconda\Lib\site-packages, 而 pyright / Pylance 不认 pyvenv.cfg 的 include-system-site-packages, 只去 .venv\Lib\site-packages 找(那里只有 pip)。 pyright 不读 pyvenv.cfg,但**认 .pth**。 改动: - pyproject.toml [tool.pyright]:venvPath = "." / venv = ".venv" / pythonVersion = "3.13",并注释了为什么必须写 - scripts/setup-venv.ps1:新增第 [2/4] 步,自动往 .venv 写 _mcm_base_site_packages.pth 指向该机 base 的 site-packages,换机重建即可 - tests/test_data.py:3 处 isna().all() 断言外面套 bool()(它的类型是 Series | bool,直接当条件 pyright 报"条件操作数无效"); 2 处故意传错类型的用例加 type: ignore[arg-type] 结果:pyright 17 errors -> 0 errors / 0 warnings;pytest 两套环境均 40 passed, 44 skipped;ruff All checks passed;setup-venv.ps1 通过 AST 解析 (纯 ASCII + LF)。 文档:docs/04-environment.md 新增坑 7(含 pyright --verbose 诊断口诀与 VS Code / PyCharm 的操作步骤)、STATUS 决策 29、CHANGELOG。
14 KiB
环境配置
记录本机(Windows / PowerShell)上 conda 与 venv 两套环境的实际配置方式、 实测数据、以及踩过的坑。相关脚本在
scripts/。状态:两套环境均已建好、版本已对齐、验证通过(2026-10-01)。
一、结论速查
| venv | conda env | |
|---|---|---|
| 路径 | D:\MCM&ICM_Toolkit\.venv |
D:\anaconda\envs\mcm-toolkit |
| 解释器 | Anaconda base,Python 3.13.9 | Python 3.13.15 |
| 占用 | 10.5 MB | 1.55 GB(+ 共用 pkgs 缓存) |
| 来源 | --system-site-packages 复用 base |
conda 从 defaults 通道安装 |
| 用途 | 轻量开发 / 离线兜底 | 跑题主力环境 |
| 缺什么 | SALib、pymoo、pyright | 无缺口 |
两套的数值计算栈已完全一致(见 §5),只差 Python 补丁号。可以放心在两套之间切换。
二、venv(轻量、离线可用)
D:\anaconda\python.exe -m venv --system-site-packages --prompt "mcm-toolkit" .venv
.venv\Scripts\python.exe -m pip install -e . --no-deps --no-build-isolation
一键:./scripts/setup-venv.ps1
为什么用 --system-site-packages
让 venv 直接复用 Anaconda base 里已有的包,零下载就有可用的科学栈, 而且只有 10.5 MB,可以安心放在项目目录里。
已验证可导入(版本随 base 走,2026-10-01 base 升级后为):
text numpy 2.4.6 scipy 1.18.1 pandas 3.0.6 matplotlib 3.11.2 scikit-learn 1.9.1 statsmodels 0.15.0 networkx 3.6.1 sympy 1.14.0
--no-deps --no-build-isolation 是必须的
--no-deps:依赖已由 base 提供,不必联网解析;--no-build-isolation:否则 pip 会新建隔离环境去下载 setuptools 构建后端。
三、conda 环境 mcm-toolkit(跑题主力)
# 一键(推荐)
.\scripts\setup-conda.ps1
# 等价的手工命令
$env:CONDA_PLUGINS_AUTO_ACCEPT_TOS = 'yes' # 见 §4 坑 1
conda create -n mcm-toolkit -y python=3.13 ^
numpy scipy pandas matplotlib scikit-learn statsmodels ^
networkx sympy openpyxl pytest ruff pip
实测:约 14.5 分钟(868 秒),下载约 3 GB,环境本体 1.55 GB。
建完后补装 pip-only 的依赖并安装本项目:
$py = 'D:\anaconda\envs\mcm-toolkit\python.exe'
& $py -m pip install SALib pymoo pyright
& $py -m pip install -e . --no-deps --no-build-isolation
这些 setup-conda.ps1 已全部自动完成。
为什么不推荐 --clone base
原以为 conda create -n X --clone base 是"本地复制、秒级完成、不用下载"。
实测不是。 在 conda 25.11 上它会重放 base 的完整包列表并逐个下载安装
(连 pandoc、m2-msys2-runtime、anaconda-navigator 这些都用不上的也照下),
跑 253 秒才下完约 2 GB 就已被中止,按比例算远慢于精准列表。
所以 setup-conda.ps1 的默认路径是精准包列表;-CloneBase 只在你确实想
要一份 base 的完整副本时才用。
断网怎么办
提前建好环境,并保留 D:\anaconda\pkgs 缓存(现在 8.4 GB)。
包已在缓存里时 conda create --offline 才能工作;否则会失败。
比赛现场不要指望临时建环境,走 venv(它 100% 离线可用)。
四、踩过的坑
坑 1 —— Anaconda ToS 插件要联网。
Anaconda 25.x 自带 conda_anaconda_tos 插件,任何 create/install 之前都会去
repo.anaconda.com 拉 ToS 元数据。断网时它不是报"没网",而是抛一长串 traceback。
$env:CONDA_PLUGINS_AUTO_ACCEPT_TOS = 'yes' # 推荐:跳过联网,保留 libmamba 求解器
conda --no-plugins create ... # 彻底关插件(退化成经典求解器,慢)
坑 2 —— envs_dirs / pkgs_dirs 必须可写。
不可写时报 NotWritableError 或
Error encountered while attempting to create cache directory。排查:
conda info --json | Select-String "envs_dirs","pkgs_dirs"
conda config --show envs_dirs pkgs_dirs
坑 3 —— 被中止的 conda create 用 conda env remove 删不干净。
本次中止后 conda env remove -n mcm-toolkit -y 跑完,D:\anaconda\envs\mcm-toolkit
仍然存在且 conda env list 里已看不到它。要手工删目录:
Remove-Item -LiteralPath 'D:\anaconda\envs\mcm-toolkit' -Recurse -Force
坑 4 —— 别把 conda env 建在项目目录里。
conda create -p ./.conda 会把 GB 级目录放进仓库,脏 .gitignore 也容易误提交。
坑 5 —— 版本漂移。 本机 base 是 2025-10 装的,defaults 通道已是 2026-10 的版本,于是新建的 conda 环境拿到的是更新的版本(pandas 从 2.3.3 跳到 3.0.6,是 major 升级)。 见 §5,写代码时注意别依赖两套环境都有的行为。
坑 6 —— conda 升级留下的 *.conda_trash 残骸会被 Python 当成包导入。
base 从 2025.12 升到 2026.07 后,D:\anaconda\Lib\site-packages\zstandard\ 里只剩一个
backend_c.cp313-win_amd64.pyd.c~.conda_trash。目录没了 __init__.py,Python 就把它当作
namespace package 导入成功,于是:
>>> import zstandard
>>> zstandard.__file__ # None —— 导入"成功"了,但什么都没拿到
>>> zstandard.__version__
AttributeError
pandas 3.0 的 import_optional_dependency("zstandard") 拿到这种半残包时,抛的不是
ModuleNotFoundError(那会被正常忽略),而是
ImportError: Can't determine version for zstandard,直接打断 pd.read_csv。
症状很迷惑:同一个脚本今天能跑明天不能跑,报错还指向 csv 读取。
怎么查(关键是 __file__ 和 __version__ 两项一起看):
& 'D:\anaconda\python.exe' -c "import zstandard; print(zstandard.__file__, getattr(zstandard,'__version__','MISSING'))"
Get-ChildItem -LiteralPath 'D:\anaconda\Lib\site-packages\zstandard' -Force
怎么修:确认 conda 记录里本来就没有这个包(conda list -n base | findstr zstandard
只该看到 backports.zstd / zstd),再把这个残骸目录改名禁用(比删掉可逆):
Move-Item -LiteralPath 'D:\anaconda\Lib\site-packages\zstandard' `
-Destination 'D:\anaconda\Lib\site-packages\zstandard.disabled-conda-trash'
改名后 import zstandard 变成正常的 ModuleNotFoundError,pandas 会安静地跳过它。
本次已按此处理,.venv 的 pd.read_csv 恢复正常。
坑 7 —— 编辑器报"无法解析导入 numpy / pandas",但解释器明明是对的。
现象:.venv 与 conda 环境里 import numpy, pandas 都正常,pytest 也全过,
只有编辑器/pyright 满屏 无法解析导入"numpy"。
原因是静态分析器自己挑了一个 python,跟你运行代码用的那个没关系。本机上
pyright --verbose 一跑就露馅:
Assuming Python version 3.14.6.final.0
Search paths:
c:\Users\guzhu\AppData\Roaming\Python\Python314\site-packages
c:\Users\guzhu\AppData\Local\Python\pythoncore-3.14-64\Lib\site-packages
... <- 一个 Anaconda 路径都没有
那个 3.14 来自 PATH 上的 python,而 PATH 上的 python 是本机唯一的 python:
where python -> C:\Users\guzhu\agent-tools\bin\python.cmd
\-> C:\Users\guzhu\.cache\codex-runtimes\...\python\python.exe
Codex 运行时的 shim(Python 3.14,没有 numpy/pandas)。分析器从 PATH 找到它, 自然解析不到科学栈。注意持久化的 User/Machine PATH 里并没有这一项, 它是被 Codex 进程临时注入的——所以"我的终端里没问题"和"工具有问题"可以同时成立。
还有第二层原因:.venv 是 --system-site-packages 建的,三方包都在
D:\anaconda\Lib\site-packages,而 pyright / Pylance 不认 pyvenv.cfg 里的
include-system-site-packages,只会去 .venv\Lib\site-packages 找——
那里只有 pip,于是照样报解析不到。
修法(两件事都要做):
- 在
pyproject.toml里把分析器钉到工作区 venv,别让它去 PATH 上碰运气:
[tool.pyright]
venvPath = "."
venv = ".venv"
pythonVersion = "3.13" # 不写就跟着 PATH 上那个 3.14 走
- 在
.venv\Lib\site-packages放一个.pth指向 base 的 site-packages。 pyright 不读pyvenv.cfg,但会读.pth:
& 'D:\anaconda\python.exe' -c "import sysconfig; print(sysconfig.get_paths()['purelib'])"
# 把输出的那一行原样写进 .venv\Lib\site-packages\_mcm_base_site_packages.pth
scripts/setup-venv.ps1 已经自动做这一步(第 [2/4] 步),换机重建 .venv 不用手动补。
改完 pyright 从 17 errors 掉到 0 errors。IDE 侧还要各做一件事:
- VS Code / Cursor:
Ctrl+Shift+P→ Python: Select Interpreter → 选D:\anaconda\envs\mcm-toolkit\python.exe(或.venv\Scripts\python.exe), 然后 Developer: Reload Window。Pylance 有缓存,不重载不生效。 - PyCharm:Settings → Project → Python Interpreter 选同一个, 再 File → Invalidate Caches / Restart。
一句诊断口诀:编辑器说"解析不到包"时,先跑 pyright --verbose 看它的
Search paths,而不是先去 pip install。
五、两套环境的实际版本(已对齐)
2026-10-01 已把 base 从 Anaconda 2025.12 升到 2026.07,两套环境版本已对齐。
| 包 | venv(继承 base) | conda mcm-toolkit |
|
|---|---|---|---|
| Python | 3.13.9 | 3.13.15 | 补丁号,可忽略 |
| numpy | 2.4.6 | 2.4.6 | ✅ 一致 |
| scipy | 1.18.1 | 1.18.1 | ✅ 一致(连 build 号都相同) |
| pandas | 3.0.6 | 3.0.6 | ✅ 一致 |
| matplotlib | 3.11.2 | 3.11.2 | ✅ 一致 |
| scikit-learn | 1.9.1 | 1.9.1 | ✅ 一致 |
| statsmodels | 0.15.0 | 0.15.0 | ✅ 一致 |
| networkx | 3.6.1 | 3.6.1 | ✅ 一致 |
| sympy | 1.14.0 | 1.14.0 | ✅ 一致 |
| pytest | 9.1.1 | 9.1.1 | ✅ 一致 |
| SALib / pymoo / pyright | 缺失 | 已装 | venv 本来就只做轻量开发 |
| BLAS 后端 | MKL | MKL | ✅ 一致 |
base 升级记录
[FENCE]powershell conda update -n base --all -y # 365 个包更新,下载 638 MB,耗时 1033 秒 conda install -n mcm-toolkit numpy=2.4.6 -y # 把项目环境对齐到 base 的 numpy [FENCE]
conda本身从 25.11.1 升到 26.7.3。- 升级前
conda list -n base --revisions里已留有 revision 记录,可回滚:conda install -n base --revision <N>。 - 踩过的坑:base 想装
numpy=2.5.3时求解器会顺手把 BLAS 从 MKL 换成 OpenBLAS (_anaconda_depends 2026.07 ..._mkl_1 → ..._openblas_1、blas 1.0-mkl → 1.0-openblas)。_anaconda_depends把 base 的 numpy 钉在 2.4.6,硬升会牵动整套线性代数后端, 所以选择把项目环境的 numpy 降到 2.4.6 来对齐,而不是动 base。 - 升级期间遇到
repo.anaconda.com读超时(默认 9.15 秒太短),已把remote_read_timeout_secs调到 120、remote_connect_timeout_secs调到 30、remote_max_retries调到 5。这几项写在~/.condarc里。
六、国内镜像(需要装新包时)
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
conda config --set show_channel_urls yes
# pip(对 venv 和 conda 环境都生效)
python -m pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
本机当前通过
http://127.0.0.1:7993的 UniClash 代理直连,未配镜像。镜像只影响下载, 不影响坑 1 的 ToS 行为。
七、可选依赖
核心 4 个包(numpy scipy pandas matplotlib)两套环境都有。其余按需:
python -m pip install -e ".[ml]" # sklearn statsmodels 已有
python -m pip install -e ".[graph]" # networkx 已有
python -m pip install -e ".[sensitivity]" # SALib conda 环境已有
python -m pip install -e ".[symbolic]" # sympy 已有
python -m pip install -e ".[moo]" # pymoo conda 环境已有
python -m pip install -e ".[excel]" # openpyxl 已有
python -m pip install -e ".[dev]" # pytest ruff pyright
缺依赖时对应函数应当给出可读的安装提示,而不是裸抛 ImportError
(写成约定,见 docs/02-architecture.md §4.6)。
八、脚本的编码约定(踩过的坑)
scripts/ 下的 .ps1 必须是纯 ASCII + UTF-8 无 BOM + LF。
原因是 Windows PowerShell 5.1 在没有 BOM 时按 ANSI(本机 GBK)解析 .ps1,
中文注释和中文消息会被拆成非法字节,报出来的却是一堆莫名其妙的
Missing closing '}' in statement block / The string is missing the terminator。
(实测:带中文的 doctor.ps1 直接语法错误;改成纯 ASCII 后立刻正常。)
两种可行方案,本项目选了第二种:
- 保留中文 → 必须存成 UTF-8 with BOM(违反 AGENTS.md 的"无 BOM"约定);
- 纯 ASCII,注释与输出用英文 → 符合 AGENTS.md,且任何编码下都能解析。← 采用
另一个相关的坑:PowerShell 5.1 向原生程序传参时会吃掉双引号,
所以 doctor.ps1 里传给 python -c 的探测代码只能用单引号字符串。
九、已知的沙箱相关现象
如果在受限环境(文件系统只读 / 无网络)里跑 matplotlib,会看到:
Matplotlib created a temporary cache directory at ... because there was an issue with
the default path (C:\Users\guzhu\.matplotlib)
这不是配置问题,是 ~\.matplotlib 不可写。正常终端里不会出现;
真遇到时设置 MPLCONFIGDIR 指向可写目录即可:
$env:MPLCONFIGDIR = "$env:TEMP\matplotlib"