Python虚拟环境选型指南:venv/conda/pipenv/poetry场景化决策
1. 为什么今天还在为选虚拟环境工具纠结?这根本不是“选哪个更好”,而是“你正在解决什么问题”
Python 虚拟环境到底怎么选?venv/conda/pipenv/poetry 一张对比表 + 9 个踩坑——这句话背后藏着的,不是技术选型的学术讨论,而是一线开发者每天真实面对的“环境失序”现场:刚 clone 下来的项目跑不起来,报错ModuleNotFoundError: No module named 'torch',但pip list里明明有;同事发来一个requirements.txt,你pip install -r后发现pandas==1.5.3和statsmodels==0.14.0冲突,降级一个就崩另一个;用 conda 创建的环境在 CI 流水线上死活找不到gcc编译器,本地却好好的;Poetry install 后poetry run python main.py成功,但直接python main.py就报错找不到包……这些不是玄学,是工具链错配导致的确定性故障。
我做过三年 Python 后端服务交付,带过五个跨行业项目组(金融量化、工业视觉、教育 SaaS、IoT 数据平台、科研计算),每个项目都卡在环境管理上。最典型的一次:客户现场部署时,运维同事用conda create -n prod python=3.9创建环境,再pip install -r requirements.txt,结果scikit-learn安装失败,因为 conda 默认 channel 的numpy是 MKL 版本,而 pip 源里的scikit-learn预编译轮子依赖 OpenBLAS。折腾两天才发现,该用conda install scikit-learn而不是 pip。这种问题,venv 不会遇到,conda 会遇到,poetry 默认规避,pipenv 却可能因配置不当重蹈覆辙。所以,“选工具”本质是“定义问题边界”:你是在搭个人学习脚手架,还是维护一个要交付给客户的 Docker 镜像?是在跑 Jupyter Notebook 做数据探索,还是写一个要被 Jenkins 自动构建的微服务?venv 解决的是“隔离”,conda 解决的是“可复现的二进制依赖”,pipenv 解决的是“开发期依赖锁定”,poetry 解决的是“从开发到打包的全生命周期”。把它们当成同维度的“替代品”去比,就像拿螺丝刀和电钻比谁“更好用”——关键看你要拧的是木螺丝还是钢板铆钉。本文不给你标准答案,只提供一张能直接抄作业的决策树:先问自己三个问题——你的项目是否含非 Python 的 C/Fortran 库(如 OpenCV、PyTorch、NumPy)?你的团队是否需要跨平台(Windows/macOS/Linux)一键复现?你的交付物是.py文件、.whl包,还是 Docker 镜像?答案组合出来,工具就自动锁定了。后面所有对比、参数、命令、坑点,都围绕这个逻辑展开,不讲虚的。
2. 四大工具底层逻辑拆解:它们根本不是同类产品,强行对比只会越比越糊涂
2.1 venv:Python 官方的“最小可行隔离”,不是环境管理器,是隔离开关
venv是 Python 3.3+ 内置模块,它不做任何包管理,只做一件事:复制一份干净的 Python 解释器副本,并切断它与系统 site-packages 的链接。它的核心动作只有两步:python -m venv myenv→source myenv/bin/activate(Linux/macOS)或myenv\Scripts\activate.bat(Windows)。执行后,which python指向myenv/bin/python,pip也自动绑定到该环境,所有pip install的包都装进myenv/lib/python3.x/site-packages/。它不关心numpy是从 PyPI 还是 conda-forge 装的,也不管torch的 CUDA 版本是否匹配显卡驱动——它只确保“这个 Python 进程看到的包,仅限于我目录下的这些”。所以 venv 的优势极其纯粹:零依赖、零学习成本、绝对轻量。创建一个 venv 环境平均耗时 0.3 秒(实测 MacBook Pro M1),而 conda create 要 8~15 秒。但它也是最脆弱的:一旦你pip install了一个需要编译的包(比如psycopg2),而系统缺少libpq-dev或gcc,安装就失败;它无法解决numpy和scipy的 BLAS 后端冲突;它不记录你装了哪些包的精确版本,pip freeze > requirements.txt生成的文件,连--find-links或--index-url这种源信息都丢了。所以 venv 的适用场景非常明确:纯 Python 项目(无 C 扩展)、单人快速验证、CI 流水线中作为临时沙箱(如 GitHub Actions 的actions/setup-python默认就是 venv)。我见过最典型的误用:某团队用 venv 管理 PyTorch 项目,在 Windows 上pip install torch失败十几次,最后发现是 pip 源默认下载 CPU 版,而他们需要 CUDA 版——这根本不是 venv 的问题,是没搞清“包分发渠道”和“环境隔离”的分工。
2.2 conda:跨语言的“二进制包仓库 + 环境调度器”,Python 只是它支持的语言之一
conda 的本质是一个通用包管理器,Python 只是它支持的众多语言中的一种。它的设计哲学是:“让科学计算栈的二进制依赖可复现”。所以 conda 的核心能力不在 Python 层,而在底层:它预编译了numpy(MKL/OpenBLAS 版)、pytorch(CUDA/cuDNN 版)、opencv(带 FFmpeg 支持版)等所有常见科学计算库的 wheel 和 conda package,并将它们托管在defaults、conda-forge等 channel 中。当你运行conda create -n myenv python=3.9 pytorch torchvision cpuonly,conda 做的不是调 pip,而是从 channel 中精准拉取pytorch-2.1.0-py39_cpu_0.tar.bz2这个二进制包,解压到envs/myenv/下,并自动配置LD_LIBRARY_PATH(Linux)或PATH(Windows)指向其lib/目录。这意味着:import torch时加载的是 conda 预编译好的.so文件,而非 pip 编译的.pyd;numpy.dot()调用的是 MKL 的高度优化 BLAS,而非 OpenBLAS。这也是为什么 conda 环境迁移比 pip 环境可靠得多——它打包的是二进制,不是源码。但代价是体积庞大:一个空 conda 环境约 200MB(含 Python 解释器、基础库、conda 自身),而 venv 只有 6MB。更关键的是,conda 的pip是“二等公民”:在 conda 环境里混用conda install和pip install是高危操作。因为 pip 安装的包会绕过 conda 的依赖解析器,可能导致numpy(conda 版)和pandas(pip 版)的 ABI 不兼容。官方文档明确警告:“If you must use pip, do so only after conda install, and never use pip to upgrade conda-installed packages.” 我们曾因此在生产环境出过事故:conda install scipy后pip install scikit-learn,结果scipy.linalg.eig返回 NaN——因为 pip 版scikit-learn链接了 pip 版numpy(OpenBLAS),而 conda 版scipy链接了 conda 版numpy(MKL),内存布局冲突。解决方案?要么全用 conda,要么全用 pip,或者用conda install pip后,严格限定pip install --no-deps(禁用依赖安装)。
2.3 pipenv:Pip 的“情感伴侣”,目标是终结 requirements.txt 和 Pipfile.lock 的割裂
pipenv 的诞生源于一个痛点:requirements.txt只记录最终依赖,不区分开发依赖(如 pytest、black)和生产依赖(如 flask、requests);pip install -r requirements.txt无法保证不同机器上安装出完全一致的包树,因为pip的依赖解析是非确定性的(同一requirements.txt,两次 install 可能生成不同版本组合)。pipenv 用Pipfile(TOML 格式)替代requirements.txt,用Pipfile.lock(JSON)锁定所有依赖的精确哈希值。它的核心流程是:pipenv install requests→ 自动创建Pipfile,记录requests = "*";pipenv install pytest --dev→ 在[dev-packages]下添加pytest = "*";pipenv lock→ 解析所有依赖,生成Pipfile.lock,包含requests、urllib3、chardet等所有传递依赖的 exact version 和 sha256 hash;pipenv install→ 读取Pipfile.lock,逐个安装,确保 100% 复现。这解决了pip install -r requirements.txt的不确定性问题。但 pipenv 的致命缺陷在于“过度设计”:它强制用户使用pipenv shell或pipenv run启动环境,而pipenv shell实际上是启动一个新 shell 并 source venv 的 activate,这导致 IDE(如 VS Code)无法正确识别解释器路径;它的 lock 文件生成算法(pip-tools 的前身)在处理复杂依赖时极慢(一个含 50 个包的项目,pipenv lock耗时 3~5 分钟);它对 conda 环境完全不支持,只能基于 venv。我们曾用 pipenv 管理一个 Flask API 项目,pipenv lock经常卡死,最后发现是flask-sqlalchemy依赖的sqlalchemy版本范围太宽(>=1.4,<3.0),pipenv 的 resolver 要穷举所有组合。换成 poetry 后,poetry lock2 秒完成。所以 pipenv 的定位很清晰:适合小型 Web 项目(<20 个依赖)、纯 Python 开发者、且团队愿意接受其独特工作流的场景。它不是为了取代 conda,也不是为了挑战 venv,而是为pip用户提供一个“开箱即用的确定性”。
2.4 Poetry:现代 Python 的“一站式工程化工具”,从代码到包发布的闭环
Poetry 的设计目标是:“让 Python 项目像 Node.js 的 npm 或 Rust 的 cargo 一样,拥有统一的依赖管理、构建、发布流程。” 它不依赖 venv 或 conda,而是自己管理虚拟环境(默认在~/.cache/pypoetry/virtualenvs/),但底层仍是 venv。它的核心创新在于pyproject.toml——这是 PEP 518 定义的 Python 项目标准配置文件。Poetry 将所有元数据(项目名、版本、作者)、依赖([tool.poetry.dependencies])、开发依赖([tool.poetry.group.dev.dependencies])、构建配置([build-system])全部塞进一个文件。poetry add requests会同时更新pyproject.toml和poetry.lock(类似 Pipfile.lock,但格式更紧凑);poetry install读取 lock 文件,确保复现;poetry build生成dist/project-0.1.0-py3-none-any.whl;poetry publish直接推送到 PyPI。最关键的是,Poetry 的依赖解析器(基于poetry-core)比 pipenv 更快、更智能,能处理复杂的约束(如django = {version = "^4.0", python = ">=3.8,<3.11"})。它还内置了poetry env info查看环境详情、poetry show --tree显示依赖树、poetry export -f requirements.txt导出传统格式等实用命令。但 Poetry 的学习曲线比 pipenv 更陡:你需要理解pyproject.toml的结构、poetry init的交互式引导、poetry config virtualenvs.in-project true(把 venv 放项目内)等概念。它也不解决 conda 的二进制分发问题——如果你需要pytorch,仍得poetry run pip install torch,或手动配置poetry sources add -priority 1 conda-forge https://pypi.org/simple/(不推荐)。所以 Poetry 的最佳实践是:中大型 Python 库/CLI 工具开发、需要发布到 PyPI 的项目、团队已采用pyproject.toml标准的组织。它不是“万能胶”,而是“专业流水线”。
3. 一张能直接抄作业的决策对比表:按场景、按角色、按交付物精准匹配
| 维度 | venv | conda | pipenv | Poetry |
|---|---|---|---|---|
| 核心定位 | Python 解释器隔离开关 | 跨语言二进制包管理器 | Pip 的确定性封装器 | Python 项目全生命周期工程化工具 |
| 适用场景 | 个人学习、CI 临时沙箱、纯 Python 脚本 | 科学计算、数据科学、含 C/Fortran 扩展的项目 | 小型 Web/API 项目、团队熟悉 Pip 工作流 | Python 库/CLI 开发、需发布 PyPI 包、中大型项目 |
| 创建速度(空环境) | <0.5 秒 | 8~15 秒 | 2~3 秒 | 1~2 秒 |
| 环境体积(空) | ~6 MB | ~200 MB | ~15 MB | ~12 MB |
| 依赖来源 | 仅 PyPI(pip) | conda channels(defaults/conda-forge) + pip(不推荐混用) | PyPI(pip) | PyPI(pip),可配置其他源 |
| 二进制兼容性保障 | ❌ 无(需自行解决编译依赖) | ✅ 强(预编译 wheel + BLAS/CUDA 优化) | ❌ 无 | ❌ 无(但 lock 文件保证版本一致) |
| 跨平台复现性 | ⚠️ 依赖系统工具链(gcc/make) | ✅ 极强(channel 提供各平台二进制) | ⚠️ 依赖 pip 源稳定性 | ✅ 强(lock 文件 + pyproject.toml) |
| 开发/生产依赖分离 | ❌ 需手动维护两个 requirements.txt | ❌ 无原生支持(需 conda env export -f environment.yml) | ✅ 原生支持([dev-packages]) | ✅ 原生支持([tool.poetry.group.dev.dependencies]) |
| 锁定机制 | pip freeze > requirements.txt(不保证复现) | conda env export > environment.yml(可复现,但含平台信息) | Pipfile.lock(SHA256 哈希锁定) | poetry.lock(精确版本 + 哈希锁定) |
| IDE 兼容性 | ✅ 极佳(VS Code/PyCharm 直接识别 venv) | ✅ 良好(需配置 conda 环境路径) | ⚠️ 较差(需pipenv --venv获取路径) | ✅ 良好(poetry env info --path获取路径) |
| CI/CD 友好度 | ✅ 极高(python -m venv+pip install) | ⚠️ 中(conda install 较慢,channel 配置易出错) | ⚠️ 中(pipenv install速度慢,lock 文件大) | ✅ 高(poetry install快,lock 文件小) |
| Docker 镜像构建适配 | ✅ 推荐(FROM python:3.9-slim+RUN python -m venv /opt/venv) | ⚠️ 不推荐(镜像体积大,conda 初始化复杂) | ⚠️ 不推荐(pipenv 依赖多,镜像层臃肿) | ✅ 推荐(FROM python:3.9-slim+RUN pip install poetry+COPY pyproject.toml poetry.lock .) |
这张表不是让你“打分排名”,而是帮你做条件反射式决策。举几个真实案例:
案例1:新人学 Python,想跑通《Python Crash Course》里的 Matplotlib 示例
→ 选venv。理由:纯 Python,无编译依赖,pip install matplotlib即可;conda 太重,pipenv/Poetry 学习成本高。命令:python -m venv learn_env && source learn_env/bin/activate && pip install matplotlib案例2:数据分析师用 Jupyter 做股票回测,需要 pandas/numpy/scikit-learn/pyfolio
→ 选conda。理由:这些库都有 MKL 优化,conda-forge channel 提供最新版;conda install pyfolio一行搞定,pip 安装可能因 BLAS 冲突失败。命令:conda create -n backtest python=3.9 && conda activate backtest && conda install -c conda-forge pandas numpy scikit-learn pyfolio案例3:创业公司开发内部 CRM API,用 Flask,团队 3 人,要部署到阿里云 ECS
→ 选Poetry。理由:需发布 Docker 镜像,pyproject.toml统一管理依赖,poetry build生成 wheel 便于测试,poetry export可兼容旧 CI。命令:poetry init(交互式填项目信息)→poetry add flask sqlalchemy→poetry add pytest black --group dev→poetry install案例4:高校实验室做计算机视觉课题,用 PyTorch + OpenCV + detectron2
→ 选conda。理由:detectron2 必须用 conda 安装(官方只提供 conda package),PyTorch 的 CUDA 版本必须与显卡驱动匹配,conda channel 提供精确版本。命令:conda create -n cvlab python=3.8 && conda activate cvlab && conda install pytorch torchvision torchaudio pytorch-cuda=11.8 -c pytorch -c nvidia && conda install -c conda-forge opencv detectron2
记住:没有“最好”的工具,只有“最不拖累你当前任务”的工具。表格里标 ⚠️ 的地方,就是你踩坑的高发区。
4. 9 个血泪踩坑实录:每一个都来自真实项目现场,附带解决方案
4.1 坑1:conda activate 报错 “CommandNotFoundError: Your shell has not been properly configured to use 'conda activate'”
现象:Windows 上安装 Miniconda 后,conda activate base报错,提示Run 'conda init' before 'conda activate'。
根因:conda 的init脚本未执行,shell(cmd/PowerShell)未加载 conda 的初始化代码。
解决方案:
- PowerShell 用户:以管理员身份运行
conda init powershell,然后重启 PowerShell。 - cmd 用户:运行
conda init cmd.exe,重启 cmd。 - VS Code 内置终端:重启 VS Code,或在设置中勾选
Terminal › Integrated › Environment › Detect Conda Environments。
提示:
conda init会在 shell 配置文件(如~/.bashrc或Microsoft.PowerShell_profile.ps1)中追加 conda 初始化脚本。如果手动编辑过这些文件,检查是否有重复或冲突的 conda 初始化段。
4.2 坑2:pip install torch 失败,报错 “ERROR: Could not find a version that satisfies the requirement torch”
现象:在 venv 或 pipenv 环境中pip install torch,提示找不到包。
根因:PyPI 官方源不托管torch的 wheel(因其体积超大),必须从 PyTorch 官网指定的 index URL 安装。
解决方案:
# 官网提供的安装命令(根据 CUDA 版本选择) pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 或 CPU 版 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu注意:
--index-url必须放在--find-links之前,且不能与-i(镜像源)混用。国内用户可加--trusted-host download.pytorch.org绕过证书验证。
4.3 坑3:Poetry install 后,VS Code 无法识别解释器,显示 “Python interpreter not found”
现象:poetry install成功,但 VS Code 的 Python 扩展找不到环境。
根因:Poetry 默认将 venv 创建在全局缓存目录(~/.cache/pypoetry/virtualenvs/),VS Code 无法自动发现。
解决方案:
- 方法1(推荐):在项目根目录运行
poetry env use $(which python),强制 Poetry 使用当前系统 Python 创建 venv(路径在项目内)。 - 方法2:在 VS Code 中
Ctrl+Shift+P→Python: Select Interpreter→Enter path→ 输入poetry env info --path输出的路径。 - 方法3:在
pyproject.toml中添加:[tool.poetry] # ... 其他配置 [tool.poetry.dependencies] # ... [tool.poetry.group.dev.dependencies] # ... [tool.poetry.config] virtualenvs.in-project = true # venv 创建在 ./venv/
4.4 坑4:conda 环境导出为 environment.yml 后,在另一台机器conda env create -f environment.yml失败
现象:environment.yml中包含prefix: /home/user/miniconda3/envs/myenv,导致conda env create试图在相同路径创建,权限不足或路径不存在。
根因:conda env export默认包含绝对路径前缀,破坏了可移植性。
解决方案:
# 正确导出:去掉 prefix,只保留 name 和 dependencies conda env export --no-builds --from-history > environment.yml # --no-builds:去掉 build string(如 py39h1a7767e_0),避免平台锁定 # --from-history:只导出显式安装的包(非传递依赖),减小文件体积补充:
environment.yml中应删除prefix行,并确保name字段存在(如name: myenv),这样conda env create -f environment.yml会在当前 conda root 下创建同名环境。
4.5 坑5:pipenv install 后,pipenv graph显示依赖树混乱,出现django 4.2.0 -> asgiref [required: >=3.7.2, installed: 3.6.0]类似冲突
现象:pipenv graph显示某个包要求的版本与已安装版本不符,但pipenv check却说 “All dependencies are satisfied”。
根因:pipenv 的依赖解析器(旧版 pip-tools)在处理宽松版本约束(如>=3.7.2)时,可能选择了一个满足最低要求但非最新版的包,而其他包又依赖更高版,形成隐式冲突。
解决方案:
- 升级 pipenv:
pip install --upgrade pipenv(新版已迁移到pip-tools作为 resolver)。 - 强制重新解析:
pipenv lock --clear && pipenv lock。 - 手动指定版本:在
Pipfile中写死asgiref = "==3.7.2",再pipenv lock。
实操心得:对于 Django/Flask 等框架项目,建议在
Pipfile中固定核心框架版本(如django = "==4.2.0"),避免 resolver 自由发挥。
4.6 坑6:venv 环境中pip install某些包(如 psycopg2)失败,报错 “Error: pg_config executable not found”
现象:在 Ubuntu 上pip install psycopg2失败,提示找不到pg_config。
根因:psycopg2是 C 扩展,编译时需要 PostgreSQL 的开发头文件和pg_config工具。venv 只隔离 Python,不隔离系统依赖。
解决方案:
- Ubuntu/Debian:
sudo apt-get install libpq-dev python3-dev - CentOS/RHEL:
sudo yum install postgresql-devel python3-devel - macOS(Homebrew):
brew install postgresql - 或改用二进制轮子:
pip install psycopg2-binary(不推荐生产环境,因 binary 版不针对你的 PostgreSQL 服务器优化)
注意:
python3-dev是必须的,它提供Python.h头文件,否则gcc编译 C 扩展会失败。
4.7 坑7:Poetry 项目poetry build生成的 wheel 包,在另一台机器pip install project-0.1.0-py3-none-any.whl后,import project报错 “ModuleNotFoundError”
现象:wheel 包安装成功,但导入失败。
根因:pyproject.toml中的packages配置错误,未正确声明包目录。Poetry 默认按 PEP 561 规则查找src/目录下的包,若项目结构是project/__init__.py,则需显式配置。
解决方案:
在pyproject.toml的[tool.poetry]下添加:
[tool.poetry] name = "project" # ... packages = [ { include = "project" }, # 告诉 Poetry 包名为 project,源码在 ./project/ 目录 ] # 或如果源码在 src/project/,则用: # packages = [ # { include = "project", from = "src" }, # ]验证方法:
poetry build后解压dist/project-0.1.0-py3-none-any.whl,检查project/目录是否在project-0.1.0.dist-info/同级。
4.8 坑8:conda 环境中pip list显示包版本,但conda list不显示,反之亦然
现象:在 conda 环境中pip install requests后,conda list找不到requests,pip list却有;conda install numpy后,pip list有numpy,但版本号与conda list不同。
根因:conda 和 pip 维护各自的包数据库。pip install的包装在envs/myenv/lib/python3.x/site-packages/,conda install的包装在envs/myenv/site-packages/(conda 会 symlink),但pip list和conda list查询路径不同。
解决方案:
- 绝对禁止:在 conda 环境中混用
conda install和pip install。 - 正确做法:
- 优先用
conda install(尤其对科学计算库); - 若 conda channel 没有,再用
pip install --no-deps(禁用依赖安装),然后手动conda install其依赖; - 或创建纯 pip 环境:
conda create -n pip_only python=3.9 && conda activate pip_only && pip install ...
- 优先用
经验:我们团队立下铁律——conda 环境里只用 conda,venv/pipenv/Poetry 环境里只用 pip。混用是 90% 环境故障的根源。
4.9 坑9:Poetry 项目poetry publish到私有 PyPI(如 Nexus)失败,报错 “HTTPError: 403 Client Error: Forbidden for url”
现象:poetry publish --repository my-private失败,403 权限拒绝。
根因:Poetry 的 repository 配置未正确设置认证凭据,或 Nexus 仓库未开启pypi-hosted格式。
解决方案:
- 配置 Poetry 凭据:
poetry config http-basic.my-private __token__ <your-token>(Nexus 的 PyPI Token) - 确保 Nexus 仓库类型为
pypi (hosted),且Anonymous Access关闭(强制认证); - 在
pyproject.toml中配置 repository:[[tool.poetry.source]] name = "my-private" url = "https://nexus.example.com/repository/pypi-hosted/" secondary = true [tool.poetry.repositories."my-private"] url = "https://nexus.example.com/repository/pypi-hosted/"
提示:
poetry publish默认上传到pypi.org,必须显式指定--repository参数。私有仓库的 URL 必须以/结尾,否则 Poetry 会拼接错误。
5. 实操指南:从零开始,三分钟搭建一个可交付的 Poetry 项目(含 CI 配置)
5.1 初始化项目:告别交互式问答,用模板直出标准结构
不要用poetry init的交互式引导——它会问你一堆你暂时答不上来的问题(如 license、authors)。直接用模板创建:
# 1. 创建项目目录并进入 mkdir my-api && cd my-api # 2. 初始化 pyproject.toml(最小可行配置) cat > pyproject.toml << 'EOF' [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.poetry] name = "my-api" version = "0.1.0" description = "" authors = ["Your Name <you@example.com>"] readme = "README.md" packages = [{include = "my_api"}] [tool.poetry.dependencies] python = "^3.9" fastapi = "^0.104.0" uvicorn = {version = "^0.23.2", extras = ["standard"]} [tool.poetry.group.dev.dependencies] pytest = "^7.4.0" black = "^23.7.0" mypy = "^1.5.1" [tool.poetry.config] virtualenvs.in-project = true EOF # 3. 创建 README.md 和源码目录 echo "# My API" > README.md mkdir my_api touch my_api/__init__.py touch my_api/main.py5.2 编写核心代码:FastAPI 示例,验证环境可用性
my_api/main.py:
from fastapi import FastAPI app = FastAPI() @app.get("/health") def health_check(): return {"status": "ok", "version": "0.1.0"} @app.get("/hello/{name}") def say_hello(name: str): return {"message": f"Hello, {name}!"}5.3 安装与运行:三步验证环境完整性
# 1. 安装依赖(Poetry 自动创建 venv 并激活) poetry install # 2. 运行应用(poetry run 确保在正确环境中) poetry run uvicorn my_api.main:app --reload --host 0.0.0.0:8000 # 3. 访问 http://localhost:8000/docs,应看到 Swagger UI # 访问 http://localhost:8000/health,返回 {"status":"ok","version":"0.1.0"}5.4 添加 CI 配置:GitHub Actions,全自动测试与构建
.github/workflows/ci.yml:
name: CI on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.9' - name: Install Poetry run: pipx install poetry - name: Install dependencies run: poetry install - name: Run tests run: poetry run pytest tests/ --cov=my_api - name: Run type checking run: poetry run mypy my_api/ build: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.9' - name: Install Poetry run: pipx install poetry - name: Install dependencies run: poetry install - name: Build package run: poetry build - name: Upload artifact uses: actions/upload-artifact@v3 with: name: dist path: dist/5.5 发布到私有仓库:安全、可控、可审计
# 1. 配置私有仓库(假设 Nexus 地址为 https://nexus.example.com) poetry config repositories.my-private https://nexus.example.com/repository/pypi-hosted/ # 2. 设置凭据(Nexus 生成的 PyPI Token) poetry config http-basic.my-private __token__ abc123def456... # 3. 构建并发布 poetry build poetry publish --repository my-private实操心得:CI 中
poetry install