Day 7: 开发环境自动化
学习目标
完成今天的学习后,你将能够:
- 管理Python虚拟环境
- 自动化依赖管理
- 配置开发工具
- 实现代码规范检查
技术原理
虚拟环境管理
Python虚拟环境用于隔离项目依赖:
bash
# 创建虚拟环境
python -m venv myenv
# 激活虚拟环境
source myenv/bin/activate # Linux/Mac
myenv\Scripts\activate # Windows
# 停用虚拟环境
deactivate依赖管理工具
1. pip + requirements.txt
bash
# 生成依赖文件
pip freeze > requirements.txt
# 安装依赖
pip install -r requirements.txt2. Poetry
bash
# 初始化项目
poetry init
# 添加依赖
poetry add requests
# 安装依赖
poetry install3. Pipenv
bash
# 安装依赖
pipenv install requests
# 激活环境
pipenv shell代码规范工具
- flake8:代码风格检查
- black:代码格式化
- isort:导入排序
- mypy:类型检查
- pylint:代码分析
案例:开发环境一键配置
创建一个开发环境配置脚本,实现:
- 自动创建虚拟环境
- 安装项目依赖
- 配置开发工具
- 设置代码规范检查
应用场景
1. 团队协作
- 统一开发环境
- 简化新人入职流程
- 减少环境问题
2. 项目管理
- 依赖版本控制
- 环境隔离
- 快速切换项目
3. 持续集成
- 自动化测试环境
- 构建环境一致性
- 部署环境管理
代码案例
案例1:环境配置脚本
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
开发环境配置脚本
功能:一键配置Python开发环境
"""
import os
import sys
import subprocess
import shutil
from pathlib import Path
class DevEnvironmentSetup:
"""开发环境配置器"""
def __init__(self, project_dir='.'):
self.project_dir = Path(project_dir).resolve()
self.venv_dir = self.project_dir / 'venv'
self.requirements_file = self.project_dir / 'requirements.txt'
def create_virtualenv(self):
"""创建虚拟环境"""
print("创建虚拟环境...")
if self.venv_dir.exists():
print(f"虚拟环境已存在: {self.venv_dir}")
return
subprocess.run([sys.executable, '-m', 'venv', str(self.venv_dir)], check=True)
print(f"虚拟环境创建成功: {self.venv_dir}")
def get_pip_path(self):
"""获取pip路径"""
if sys.platform == 'win32':
return self.venv_dir / 'Scripts' / 'pip.exe'
return self.venv_dir / 'bin' / 'pip'
def install_requirements(self):
"""安装依赖"""
print("安装项目依赖...")
pip_path = self.get_pip_path()
if not self.requirements_file.exists():
print("requirements.txt 不存在,跳过依赖安装")
return
# 升级pip
subprocess.run([str(pip_path), 'install', '--upgrade', 'pip'], check=True)
# 安装依赖
subprocess.run([str(pip_path), 'install', '-r', str(self.requirements_file)], check=True)
print("依赖安装完成")
def install_dev_tools(self):
"""安装开发工具"""
print("安装开发工具...")
pip_path = self.get_pip_path()
dev_tools = [
'flake8', # 代码风格检查
'black', # 代码格式化
'isort', # 导入排序
'pytest', # 测试框架
'pytest-cov', # 测试覆盖率
'mypy', # 类型检查
]
subprocess.run([str(pip_path), 'install'] + dev_tools, check=True)
print("开发工具安装完成")
def create_config_files(self):
"""创建配置文件"""
print("创建配置文件...")
# flake8配置
flake8_config = self.project_dir / '.flake8'
if not flake8_config.exists():
flake8_config.write_text("""[flake8]
max-line-length = 88
extend-ignore = E203
exclude = .git,__pycache__,build,dist,venv
""")
# black配置
pyproject_toml = self.project_dir / 'pyproject.toml'
if not pyproject_toml.exists():
pyproject_toml.write_text("""[tool.black]
line-length = 88
target-version = ['py38']
include = '\\.pyi?$'
exclude = '''
/(
\\.git
| \\.hg
| \\.mypy_cache
| \\.tox
| \\.venv
| _build
| buck-out
| build
| dist
)/
'''
""")
# isort配置
isort_config = self.project_dir / '.isort.cfg'
if not isort_config.exists():
isort_config.write_text("""[isort]
profile = black
line_length = 88
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
""")
print("配置文件创建完成")
def create_gitignore(self):
"""创建.gitignore文件"""
print("创建.gitignore文件...")
gitignore = self.project_dir / '.gitignore'
if not gitignore.exists():
gitignore.write_text("""# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
""")
print(".gitignore创建完成")
def setup(self):
"""执行完整配置"""
print("=" * 50)
print("开始配置开发环境")
print("=" * 50)
self.create_virtualenv()
self.install_requirements()
self.install_dev_tools()
self.create_config_files()
self.create_gitignore()
print("\n" + "=" * 50)
print("开发环境配置完成!")
print("=" * 50)
print(f"\n项目目录: {self.project_dir}")
print(f"虚拟环境: {self.venv_dir}")
print("\n激活虚拟环境:")
if sys.platform == 'win32':
print(f" {self.venv_dir}\\Scripts\\activate")
else:
print(f" source {self.venv_dir}/bin/activate")
def main():
"""主函数"""
import argparse
parser = argparse.ArgumentParser(description='Python开发环境配置工具')
parser.add_argument('project_dir', nargs='?', default='.', help='项目目录')
args = parser.parse_args()
setup = DevEnvironmentSetup(args.project_dir)
setup.setup()
if __name__ == "__main__":
main()案例2:代码格式化工具
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
代码格式化工具
功能:自动格式化Python代码
"""
import os
import subprocess
import sys
from pathlib import Path
class CodeFormatter:
"""代码格式化器"""
def __init__(self, project_dir='.'):
self.project_dir = Path(project_dir).resolve()
def run_command(self, cmd, description):
"""执行命令"""
print(f"\n{description}...")
print(f"执行命令: {' '.join(cmd)}")
try:
result = subprocess.run(
cmd,
cwd=self.project_dir,
capture_output=True,
text=True
)
if result.stdout:
print(result.stdout)
if result.stderr:
print(result.stderr)
return result.returncode == 0
except FileNotFoundError:
print(f"错误:找不到命令 '{cmd[0]}',请先安装")
return False
def format_with_black(self, check_only=False):
"""使用black格式化"""
cmd = ['black']
if check_only:
cmd.append('--check')
cmd.extend(['--line-length', '88', '.'])
return self.run_command(cmd, "使用black格式化代码")
def sort_imports(self, check_only=False):
"""使用isort排序导入"""
cmd = ['isort']
if check_only:
cmd.append('--check-only')
cmd.extend(['--profile', 'black', '.'])
return self.run_command(cmd, "使用isort排序导入")
def check_style(self):
"""使用flake8检查代码风格"""
cmd = ['flake8', '--max-line-length', '88', '.']
return self.run_command(cmd, "使用flake8检查代码风格")
def check_types(self):
"""使用mypy检查类型"""
cmd = ['mypy', '--ignore-missing-imports', '.']
return self.run_command(cmd, "使用mypy检查类型")
def run_tests(self):
"""运行测试"""
cmd = ['pytest', '-v', '--cov=.', '--cov-report=term-missing']
return self.run_command(cmd, "运行测试")
def format_all(self, check_only=False):
"""执行所有格式化操作"""
print("=" * 50)
print("开始代码格式化和检查")
print("=" * 50)
results = []
results.append(("导入排序", self.sort_imports(check_only)))
results.append(("代码格式化", self.format_with_black(check_only)))
results.append(("代码风格检查", self.check_style()))
print("\n" + "=" * 50)
print("执行结果汇总")
print("=" * 50)
for name, success in results:
status = "✓ 通过" if success else "✗ 失败"
print(f"{name}: {status}")
return all(success for _, success in results)
def main():
"""主函数"""
import argparse
parser = argparse.ArgumentParser(description='Python代码格式化工具')
parser.add_argument('project_dir', nargs='?', default='.', help='项目目录')
parser.add_argument('--check', action='store_true', help='仅检查,不修改')
parser.add_argument('--black', action='store_true', help='仅运行black')
parser.add_argument('--isort', action='store_true', help='仅运行isort')
parser.add_argument('--flake8', action='store_true', help='仅运行flake8')
parser.add_argument('--mypy', action='store_true', help='仅运行mypy')
parser.add_argument('--test', action='store_true', help='运行测试')
args = parser.parse_args()
formatter = CodeFormatter(args.project_dir)
if args.black:
formatter.format_with_black(args.check)
elif args.isort:
formatter.sort_imports(args.check)
elif args.flake8:
formatter.check_style()
elif args.mypy:
formatter.check_types()
elif args.test:
formatter.run_tests()
else:
formatter.format_all(args.check)
if __name__ == "__main__":
main()课后练习
练习1:虚拟环境管理
- 创建一个虚拟环境管理脚本
- 支持创建、激活、删除环境
- 支持环境克隆和导出
练习2:依赖管理
- 实现依赖版本锁定
- 支持依赖更新和回滚
- 检测依赖冲突
练习3:代码规范
- 配置代码规范检查工具
- 集成到Git提交流程
- 生成规范检查报告
常见问题
Q1: 如何选择虚拟环境工具?
A: 推荐使用venv(内置)或Poetry(现代项目)。
Q2: 如何处理依赖冲突?
A: 使用pip check检查冲突,或使用Poetry自动解决。
Q3: 如何在团队中统一代码风格?
A: 使用pre-commit钩子自动检查和格式化。
下一步学习
完成今天的学习后,建议你:
- 熟悉虚拟环境和依赖管理
- 配置代码规范检查工具
- 尝试自动化开发环境配置
- 准备进入Day 8的学习:测试自动化
明天我们将学习如何编写自动化测试。