Django REST framework 代码风格实战

980 阅读3分钟

写在前面

Django REST framework 登录之实战

今天话题的起因主要是每个开发者都有自己的编码习惯这是好事同时也是坏事,主要是风格不一样在阅读代码的时候效率比较低。 所以聊点开发规范相关的东西,比如 代码风格 强制校验,主要涉及到的有 PEP8 flake8 , 还会结合git的操作对代码自动格式化的配置。 目的是为了提高代码质量,提高团队协作效率。

正文开始

1. 环境的准备

代码仓库+版本控制

  • pre-commit pre-commit hook 在git commit 时触发python 代码检查。它会兼容前端 precommit hook。
  • black python 代码格式化工具, 帮助格式化python 代码
  • flake8 代码风格检查,如检查是否符合PEP8
# 1. 安装git(详细配置略过)
brew install git

# 2. 安装 pre-commit
pipenv install pre-commit

2. 关于python的代码格式

PEP 8 -- Style Guide for Python Code 总结来说 就是 python为了规范大家的代码风格做出一些代码风格的规定,比如:空格使用、命名规范、注释风格等

3. 关于 git hook

git hooks是一些自定义的脚本,用于控制git工作的流程。在客户端初始化仓库的时候会在.git/hooks自动生成许多脚本 ;类似

$ ls .git/hooks 
applypatch-msg.sample 
commit-msg.sample
fsmonitor-watchman.sample
post-update.sample
pre-applypatch.sample
pre-commit.sample   
pre-push.sample
pre-rebase.sample
pre-receive.sample
prepare-commit-msg.sample
update.sample

4. 格式配置

# 1. 新增文件 .pre-commit-config.yaml
repos:
- repo: https://github.com/ambv/black
  rev: stable
  hooks:
    - id: black
      language_version: python3.6

# 2. 自动配置pre-commit
$ pre-commit install
pre-commit installed at .git/hooks/pre-commit

5. 验证结果

# 1. 选中需要提交的代码
git add demo/mock_view.py

# 2. commit 代码

$ git commit -m "新增格式校验"                                                     
[INFO] Installing environment for https://github.com/ambv/black.
[INFO] Once installed this environment will be reused.
[INFO] This may take a few minutes...
black....................................................................Failed
- hook id: black
- files were modified by this hook

reformatted demo/mock_view.py
All done! ✨ 🍰 ✨
1 file reformatted.

# 3. 再次提交代码 
git add demo/mock_view.py
git commit -m "新增格式校验"
black....................................................................Passed
[master abbc9d7] 新增格式校验
 4 files changed, 153 insertions(+), 34 deletions(-)
 create mode 100644 .pre-commit-config.yaml

image.png

可以看到第一次commit的时候pre-commit会自动对我需要提交的代码格式化而且会有个failed的提示;再次add commit 之后就有 passed 的提示就代表成功;如果一只 failed 可能需要收到解决问题。

总结

一些问题汇总

  1. 第一次 commit 安装包的时候 出现 Could not find a version that satisfies the requirement typed-ast>=1.4.2; python_version < "3.8" 分析具体的日志发现是我全局 pip的配置影响的,直接删除文件就好。
$ cat ~/.pip/pip.conf
[global]
timeout = 60
index-url = http://pypi.douban.com/simple
trusted-host = pypi.douban.com
format=columns

  1. Windows同学出现 代码格式化失败问题

在Windows 10 平台上安装配置工具套装完毕后,git commit 如果出现类似 "文件未找到" 或 “file not found” 的问题, 需要修改pre-commit脚本以兼容windows。修改详情如下

# vim .git/hooks/pre-commit
...
def _run_legacy():
    if __file__.endswith('.legacy'):
        raise SystemExit(
            "bug: pre-commit's script is installed in migration mode\n"
            'run `pre-commit install -f --hook-type {}` to fix this\n\n'
            'Please report this bug at '
            'https://github.com/pre-commit/pre-commit/issues'.format(
                HOOK_TYPE,
            ),
        )
 
    if HOOK_TYPE == 'pre-push':
        stdin = getattr(sys.stdin, 'buffer', sys.stdin).read()
    else:
        stdin = None
 
    legacy_hook = os.path.join(HERE, '{}.legacy'.format(HOOK_TYPE))
    if os.access(legacy_hook, os.X_OK):
        cmd = _norm_exe(legacy_hook) + (legacy_hook,) + tuple(sys.argv[1:])
        """
        此处修改:
        在subprocess.Popen 添加参数 “shell=True”以避免windows 平台路径问题。
        修改前: proc = subprocess.Popen(cmd, stdin=subprocess.PIPE if stdin else None)
        修改后: proc = subprocess.Popen(cmd, stdin=subprocess.PIPE if stdin else None, shell=True)
         """
        proc = subprocess.Popen(cmd, stdin=subprocess.PIPE if stdin else None, shell=True)
        proc.communicate(stdin)
        return proc.returncode, stdin
    else:
        return 0, stdin
  1. windows用户可能会出现前端无法格式化文件的情况,原因是因为在执行.git/hooks/pre-commit.legacy时,没法通过/bin/sh执行。

解决方案:(注意是修改shell的执行路径,根据具体安装位置修改)

将.git/hooks/pre-commit.legacy的首行替换为本地git下面的sh.exe的路径。

修改前:#!/bin/sh

修改后:#!D:\programs\Git\usr\bin\sh.exe

4. pre-commit 干了什么? 截取 pre-commit的一段代码,可以看到我们在 pre-commit install 的时候将配置文件以及需要执行的脚本配置到 .git/hooks/pre-commit 中;然后在commit的时候自动调用。

# start templated
INSTALL_PYTHON = '/Users/shuai/.local/share/virtualenvs/demo-lBAuzz5g/bin/python'
ARGS = ['hook-impl', '--config=.pre-commit-config.yaml', '--hook-type=pre-commit']
# end templated
ARGS.extend(('--hook-dir', os.path.realpath(os.path.dirname(__file__))))
ARGS.append('--')
ARGS.extend(sys.argv[1:])

DNE = '`pre-commit` not found.  Did you forget to activate your virtualenv?'
if os.access(INSTALL_PYTHON, os.X_OK):
    CMD = [INSTALL_PYTHON, '-mpre_commit']
elif which('pre-commit'):
    CMD = ['pre-commit']
else:
    raise SystemExit(DNE)

参考资料