当前的一些Python项目使用Make调用flake8工具来进行代码格式检查,即使检查出不符合规范的代码仍需要手动定位到指定文件进行格式化操作,且这些操作并不是强制执行,这就导致开发人员经常性的忘记检查代码规范就提交了一个commit,并且可以成功将不合规范的代码推到远程分支上,然后git commit log上充斥着大量的“fix: flake8”,“fix: 规范”等毫无意义的信息(题外话:包括一些接连几条重复的log,这可以通过git commit --amend来追加修改),看起来难受,也增大了blame的难度,浪费时间。
此外,Makefile中的flake8忽略了“F401’module imported but unused’”是不应该的,请只导入需要的包(其实这在PyCharm和VSCode中都会置灰提示)。
安装 pre-commit
为了解决这些问题以及带来更多自动化,可以通过使用githooks提供的pre-commit 在每一次commit前自动进行代码检查和格式化,如果pre-commit返回了错误状态码,则该次提交将不能通过。幸运的是,当前流行的一个使用Python编写的同名工具 pre-commit 使得只需要在项目根目录下添加一个.pre-commit-config.yaml文件并写上相应的配置即可使用很多代码检查和格式化工具,实现自动代码检查和格式化。
对于Python项目,可使用的工具有:
pip install pre-commit
pre-commit installs
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
# pre-commit==2.13.0
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/PyCQA/isort
rev: 5.8.0
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
rev: 3.9.2
hooks:
- id: flake8
- repo: https://github.com/psf/black
rev: 21.6b0
hooks:
- id: black
exclude: |
(?x)^(
etc|
.*?/migrations|
bmiss/settings/instance.*|
.*?proto.*
)
用pre-commit install安装git hooks到你的.git/目录
如果想要自定义一些配置的时候需要写.flake8的配置文件
ignore忽略
exclude除了这写文件夹之外
[flake8]
# E203 whitespace before ':'
# E266 Too many leading '#' for block comment
# E501,B950 Line too long
# W503 Line break occurred before a binary operator
# W504 line break after binary operator
# F405;403 Variable may be undefined; import * unable to detect undefined names
# C901 Function is too complex
# '# noqa' ignore in-line error
# '# flake8: noqa' ignore entire file
ignore = E203, E266, E402, E501, W503, W504, B950, F405, F403, C901
max-complexity = 50
select = B,C,E,F,W
exclude =
migrations
static
taps_proto
如果你觉得没有必要强制要求不能定义变量而不使用(从输出可以看出这个规范的编号为F841),可以在项目根目录建一个 .flake8配置文件,如下图。更加详细的配置请看官方文档。
安装之后第一次使用会初始化python环境并根据repo指向从对应地址拉取所用到的工具,之后便可以正常使用。
示例:
某变动的文件代码为
import os
import sys
def function(very_long_variable_name, this, that):
if very_long_variable_name is not None and \
very_long_variable_name.field > 0 or \
very_long_variable_name.is_debug:
z = 'hello ' + 'world'
return
else:
world = 'world'
a = 'hello {}'.format(world)
f = rf'hello {world}'
if (this
and that): f = 'hello ''world'# FIXME: https://github.com/python/black/issues/26
return f
执行git commit -a -m “feat: Add a function function”
输出如下
(helloworld) ➜ [/Users/edy/projects/helloworld] git:(master) ✗ git commit -a -m “feat: Add a function function”
Trim Trailing Whitespace…Passed
Fix End of Files…Failed
import os
import sys
def function(very_long_variable_name, this, that):
if (
very_long_variable_name is not None
and very_long_variable_name.field > 0
or very_long_variable_name.is_debug
):
z = "hello " + "world"
return z
else:
world = "world"
a = "hello {}".format(world)
f = rf"hello {world}"
if this and that:
f = "hello " "world" # FIXME: https://github.com/python/black/issues/26
return f
根据提示移除未使用的导入和变量后再此提交git commit即可成功。
这样,通过pre-commit减轻了因开发者个人导致的代码格式不规范继而影响多人协作开发的问题,所有人的代码格式都将由black来控制。
Black is the uncompromising Python code formatter. By using it, you
agree to cede control over minutiae of hand-formatting. In return,
Black gives you speed, determinism, and freedom from pycodestyle
nagging about formatting. You will save time and mental energy for
more important matters.
文件首行使用"# flake8: noqa"可以忽略整个文件的flake8检查,这对那些只供导入的__init__.py很有用,但不该滥用
行注释“# noqa”可以忽略该行flake8检查
.pre-commit-config.yaml文件中“exclude”参数可以排除检查的文件,“files”则是检查哪些文件