为什么需要弄脚手架?
平时,主要是开发一些工具给自己或部门使用,因此对代码管理比较随意,也不需要其他人查看或修改代码。近期,有个工具要推广给其他人使用,为了方便他们修改代码,要增加注释之类的工作。在这个过程中,发现了一大段问题,比如地址的引用,存在较多相对地址,容易发生错误,代码命名不规范等一大堆规范性问题。
为了改善自己的编码习惯、减少规范性问题,花了一些时间查找、研究Python项目管理的方式,经过几次折腾后,总算确定了自己的项目管理方式(短期内应该不会再调整了)。
环境管理
我原先使用的是Anaconda,但是后面觉得有点臃肿,适合做数据分析或机器学习,但不太适合做开发,因此改用 pipenv 进行环境管理(机器学习开发环境也是用pipenv)。
创建虚拟环境
pipenv install --python version
上述命令会生成Pipfile和Pipfile.lock,且会使用pipenv创建虚拟环境,自动生成一个随机的虚拟环境目录名。般虚拟环境目录名的前缀是你创建环境时所在的项目目录名,如在myblog目录下执行命令,虚拟环境的目录名称就是myblog-Gtn4e1q9,后半部分为随机字符串。
在windows系统下执行命令,虚拟环境的文件 C:\Users\用户名.virtualenvs 文件夹下。若要修改存储地址,则要在系统新建【WORKON_HOME】的环境变量。
pipenv --venv # 获取当前虚拟环境的位置
pipenv --where # 寻找当前项目的根目录
激活虚拟环境
创建环境后会自动进入到虚拟环境中,当退出虚拟环境重新进入到虚拟环境则需要激活虚拟环境。
在项目目录下,执行如下命令,即可激活虚拟环境.
pipenv shell
激活虚拟环境后,所有的操作仅影响当前的虚拟环境。
包管理
安装依赖包到虚拟环境
建议使用pipenv来安装/卸载相关包,便于开发依赖包的管理。安装与卸载同理,不额外说明。
pipenv install module_name # 安装生产环境的依赖包
pipenv install module_name --dev # 安装开发环境的依赖包
不管是否激活虚拟环境,都可以执行pipenv install module_name来安装。
若要使用pip进行安装,则按如下命令执行:
pipenv run pip install module_name
使用pipenv安装时,可能会出现lock fail。这个让我苦恼了很久,解决方案如下:
- 跳过lock环节,先把包安装上。
pipenv install requests --skip-lock
- 查看安装包的版本号,并添加到pipfile中。
pipenv graph
3.更新pipfile.lock,重新安装虚拟环节时,依赖这个文件,不能漏了。
pipenv lock --dev
导出/安装包文件
导出依赖包
pipenv lock -r > requirements_dev.txt # 不包含开发环境的依赖包
pipenv lock -r --dev > requirements_dev.txt # 包含开发环境的依赖包
也可以使用pip进行导出,不过无法区分开发环境的依赖包。
pipenv run pip freeze > requirements.txt
根据pipfile安装依赖包
pipenv install # 不包含开发环境的依赖包
pipenv install --dev # 包含开发环境的依赖包
根据requirements安装。
pipenv install -r > requirements.txt
开发环境配置
开发环境配置,主要关注几点:代码风格统一、静态类型检查、单元测试。
使用black进行格式化我们的代码。--dev用来区分开发环境,不要忘了。
pipenv install black --dev # 安装
pipenv run black file_name/dir_name # 运行
使用isort对import进行管理。
pipenv install isort --dev # 安装
pipenv run isort file_name/dir_name # 运行
使用 flake8 保证代码风格,可以参考谷歌Python风格指南。
pipenv install flake8 --dev # 安装
pipenv run flake8 file_name/dir_name # 运行
使用 mypy 进行静态类型检查。不过,Python的类型注释还是不好用。
pipenv install mypy --dev # 安装
pipenv run mypy file_name/dir_name # 运行
用 pytest 进行测试,我用的比较少,实在是懒得写测试代码。
pipenv install pytest --dev # 安装
pipenv run pytest # 运行
以上就是主要的开发环境内容,但是每次手动执行还是比较麻烦的。因此,需要用到 Git 的 pre-commit,在提交代码前自动执行相关命令。这里需要用到 pre-commit 库。
pipenv install pre-commit --dev
然后新建.pre-commit-config.yaml,并添加下述配置。
repos:
- repo: local
hooks:
- id: isort
name: isort
stages: [commit]
language: system
entry: pipenv run isort {{cookiecutter.project_slug}}
types: [python]
- id: black
name: black
stages: [commit]
language: system
entry: pipenv run black {{cookiecutter.project_slug}}
types: [python]
- id: flake8
name: flake8
stages: [commit]
language: system
entry: pipenv run flake8 {{cookiecutter.project_slug}}
types: [python]
exclude: setup.py
- id: mypy
name: mypy
stages: [commit]
language: system
entry: pipenv run mypy
types: [python]
pass_filenames: false
- id: pytest
name: pytest
stages: [commit]
language: system
entry: pipenv run pytest
types: [python]
最后,执行下述命令生成git hooks。
pipenv run pre-commit install
快速创建项目
开发环境的配置还是有较多内容,为了减少重复工作,需要用到 cookiecutter 进行项目创建。我已经将上述内容整合到项目模板中,执行如下命令可直接创建项目。
pip install cookiecutter # 不用安装到虚拟环境。
cookiecutter https://e.coding.net/jinuobushibili/zzz_tools/ProjectTemplate.git
除上述内容外,项目模板中还包含项目目录、项目配置等多项内容。
项目代码结构
- docs(dir):项目文档库
- template(dir):模板文件库
- bin(dir):入口文件,可无
- db(dir):数据文件地址
- log(dir):项目日志文件
- conf(dir):项目配置文件
- tests(dir):测试代码
- lib(dir):自定义的模块或包
- sample(dir):关键代码文件,每个包单独目录
- _ init _.py
- main.py
- setting.py:添加了部分目录的路径变量,如db。
- README.md:项目说明文档
- requirements.txt:项目依赖的三方库
- setup.py:安装、部署、打包代码
修改项目模板
若要基于自己的需求,对项目模板进行修改的话,也是比较简单的。
变量修改
cookiecutter变量,通过 cookiecutter.json 进行修改。其中的值为默认值,在创建项目时,会要求再次确认。而变量的使用,只需在对应的文件中,使用 {{ 变量名 }}即可。但需保证文件的编码为utf-8。
目录/文件调整
cookiecutter生成的文件目录是{{cookiecutter.project_slug}},需要项目自动生成的文件要放到这个目录下。
在{{cookiecutter.project_slug}}目录下操作即可,对根目录下其他目录的修改是不会影响创建项目的。
开发环境调整
调整完以后,记得更新requirem或pipfile即可。相关操作,请查看上方对应内容。
Hooks
cookiecutter的hooks全部在hooks目录下。
- pre_gen_project.py:项目创建前
- post_gen_project.py:项目创建后
结合cookiecutter变量与hooks,可以进行许多复杂的操作。我还没怎么用。