← 返回首页
📦

Python生态全景:PyPI、打包分发、版本管理与虚拟环境

📂 python ⏱ 4 min 731 words

Python生态全景:PyPI、打包分发、版本管理与虚拟环境

Python拥有庞大的生态系统,掌握包管理、打包分发和环境管理是每个Python开发者必备的技能。本文将全面介绍Python生态的核心组成部分。

PyPI与pip:包管理基础

PyPI(Python Package Index)是Python的官方软件包仓库,pip是与之配套的包管理工具:

# 基本pip命令
pip install requests                    # 安装包
pip install requests==2.28.0           # 安装指定版本
pip install requests>=2.25.0,<3.0.0    # 安装版本范围
pip install -r requirements.txt        # 从文件安装
pip install --upgrade requests         # 升级包
pip uninstall requests                 # 卸载包

# 查看信息
pip show requests                      # 查看包信息
pip list                               # 列出已安装包
pip list --outdated                    # 列出可升级的包

# 生成依赖文件
pip freeze > requirements.txt          # 生成requirements文件
pip install -r requirements.txt        # 从requirements安装

requirements.txt最佳实践

# requirements.txt
requests==2.28.1
flask>=2.2.0,<3.0.0
sqlalchemy~=1.4.0
celery[redis]==5.2.7

# 开发依赖
pytest>=7.0.0
black>=22.0.0
mypy>=0.900

pyproject.toml:现代Python项目配置

# pyproject.toml
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.backends._legacy:_Backend"

[project]
name = "my-awesome-package"
version = "1.0.0"
description = "一个很棒的Python包"
readme = "README.md"
license = {text = "MIT"}
authors = [
    {name = "张三", email = "zhangsan@example.com"},
]
keywords = ["example", "package"]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: OSI Approved :: MIT License",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.8",
    "Programming Language :: Python :: 3.9",
    "Programming Language :: Python :: 3.10",
]
requires-python = ">=3.8"
dependencies = [
    "requests>=2.25.0",
    "click>=8.0.0",
]

[project.optional-dependencies]
dev = [
    "pytest>=7.0.0",
    "black>=22.0.0",
    "mypy>=0.900",
]
docs = [
    "sphinx>=4.0.0",
    "sphinx-rtd-theme>=1.0.0",
]

[project.urls]
Homepage = "https://github.com/example/my-awesome-package"
Documentation = "https://my-awesome-package.readthedocs.io"
Repository = "https://github.com/example/my-awesome-package"

[project.scripts]
my-cli = "my_awesome_package.cli:main"

[tool.black]
line-length = 88
target-version = ['py38', 'py39', 'py310']

[tool.mypy]
python_version = "3.8"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true

setuptools:传统打包工具

# setup.py(传统方式,现在推荐使用pyproject.toml)
from setuptools import setup, find_packages
from pathlib import Path

this_directory = Path(__file__).parent
long_description = (this_directory / "README.md").read_text(encoding='utf-8')

setup(
    name="my-package",
    version="1.0.0",
    author="张三",
    author_email="zhangsan@example.com",
    description="一个示例Python包",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/example/my-package",
    packages=find_packages(where="src"),
    package_dir={"": "src"},
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
    ],
    python_requires=">=3.8",
    install_requires=[
        "requests>=2.25.0",
    ],
    extras_require={
        "dev": ["pytest>=7.0.0"],
    },
    entry_points={
        "console_scripts": [
            "my-cli=my_package.cli:main",
        ],
    },
)

包结构组织

my-package/
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       ├── utils.py
│       └── subpackage/
│           ├── __init__.py
│           └── module.py
├── tests/
│   ├── __init__.py
│   ├── test_core.py
│   └── test_utils.py
├── docs/
├── pyproject.toml
├── README.md
├── LICENSE
└── .gitignore

版本管理策略

# 版本号管理(使用bump2version或setuptools-scm)

# .bumpversion.cfg
# [bumpversion]
# current_version = 1.0.0
# commit = True
# tag = True
#
# [bumpversion:file:pyproject.toml]
# search = version = "{current_version}"
# replace = version = "{new_version}"

# 使用setuptools-scm自动管理版本
# pyproject.toml中添加:
# [build-system]
# requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"]
#
# [tool.setuptools_scm]
# write_to = "src/my_package/_version.py"

# 语义化版本控制
# MAJOR.MINOR.PATCH
# 1.0.0 -> 1.0.1 (修复bug)
# 1.0.1 -> 1.1.0 (新功能)
# 1.1.0 -> 2.0.0 (重大变更)

虚拟环境管理

# venv(Python内置)
python -m venv myenv              # 创建虚拟环境
source myenv/bin/activate         # 激活(Linux/Mac)
myenv\Scripts\activate            # 激活(Windows)
deactivate                        # 退出

# virtualenv(第三方,功能更丰富)
pip install virtualenv
virtualenv myenv                  # 创建
virtualenv --python=3.9 myenv     # 指定Python版本

# pipenv(结合pip和virtualenv)
pip install pipenv
pipenv install requests           # 安装包并创建Pipfile
pipenv install --dev pytest       # 安装开发依赖
pipenv shell                      # 进入虚拟环境
pipenv run python script.py       # 运行命令

# poetry(现代依赖管理)
pip install poetry
poetry init                       # 初始化项目
poetry add requests               # 添加依赖
poetry add --group dev pytest     # 添加开发依赖
poetry install                    # 安装所有依赖
poetry shell                      # 进入虚拟环境
poetry build                      # 构建包

# conda(科学计算环境)
conda create -n myenv python=3.9  # 创建环境
conda activate myenv              # 激活
conda install numpy               # 安装包
conda env export > environment.yml # 导出环境
conda env create -f environment.yml # 从文件创建

现代Python项目模板

# 使用cookiecutter创建项目
# pip install cookiecutter

# 创建项目
# cookiecutter https://github.com/audreyr/cookiecutter-pypackage

# 自定义项目模板结构
project_template = """
my-project/
├── .github/
│   └── workflows/
│       ├── ci.yml
│       └── release.yml
├── src/
│   └── my_project/
│       ├── __init__.py
│       └── core.py
├── tests/
│   ├── __init__.py
│   └── test_core.py
├── docs/
├── pyproject.toml
├── README.md
├── LICENSE
├── CHANGELOG.md
└── Makefile
"""

# Makefile示例
makefile_content = """
.PHONY: help install test lint format build clean

help:  ## 显示帮助信息
\t@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | \\
\t\tawk 'BEGIN {FS = ":.*?## "}; {printf "\\033[36m%-20s\\033[0m %s\\n", $$1, $$2}'

install:  ## 安装依赖
\tpip install -e ".[dev]"

test:  ## 运行测试
\tpytest tests/ -v --cov=src/my_project

lint:  ## 代码检查
\tblack --check src/ tests/
\tmypy src/
\tflake8 src/ tests/

format:  ## 代码格式化
\tblack src/ tests/

build:  ## 构建包
\tpython -m build

clean:  ## 清理构建文件
\trm -rf dist/ build/ *.egg-info
"""

包发布流程

# 发布到PyPI的完整流程

# 1. 准备工作
# - 确保pyproject.toml配置正确
# - 更新版本号
# - 更新CHANGELOG
# - 运行测试确保通过

# 2. 构建包
# python -m build
# 这会生成dist/目录下的.whl和.tar.gz文件

# 3. 检查包
# twine check dist/*
# 确保包符合PyPI要求

# 4. 上传到TestPyPI(测试)
# twine upload --repository testpypi dist/*

# 5. 上传到PyPI
# twine upload dist/*

# 自动化发布(GitHub Actions示例)
github_actions_workflow = """
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.9'
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install build twine
      - name: Build package
        run: python -m build
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          password: ${{ secrets.PYPI_API_TOKEN }}
"""

依赖解析与锁定

# pip-tools:精确的依赖管理
# pip install pip-tools

# 生成requirements.txt
# pip-compile pyproject.toml

# 更新依赖
# pip-compile --upgrade pyproject.toml

# 安装精确版本
# pip-sync requirements.txt

# pipdeptree:查看依赖树
# pip install pipdeptree
# pipdeptree

# 安全检查
# pip install safety
# safety check

# pip-audit:漏洞扫描
# pip install pip-audit
# pip-audit

最佳实践总结

  1. 使用pyproject.toml:这是现代Python项目的标准配置文件
  2. 虚拟环境隔离:每个项目使用独立的虚拟环境
  3. 版本锁定:使用requirements.txt或lock文件锁定依赖版本
  4. 语义化版本:遵循MAJOR.MINOR.PATCH版本号规范
  5. 持续集成:在CI/CD中自动运行测试和代码检查
  6. 文档完善:提供清晰的README和使用文档
  7. 安全扫描:定期检查依赖中的安全漏洞

掌握这些Python生态工具和最佳实践,可以帮助你更高效地开发、分发和维护Python项目。