基于 Pre-commit 的 Python项目代码风格统一实践

news2025/2/6 20:27:30

背景信息

统一代码风格首先需要定义参照的规范,每个团队可能会有自己的规范,我们选择的规范是 yapf + mypy + isort,如果保证所有的研发人员都遵循相关规范呢?

  1. 鼓励 IDE 中对应的插件的安装,通过直接对应的插件,在编写代码阶段就能实时发现不符合规范的情况,修改成本最低;
  2. 通过 Pre-commit 在创建 commit 时执行检查,并进行必要的自动格式化,提供统一的规范约束,成本次之;
  3. 在发起 Pull-Request 时拉取代码执行检查,并异步返回检查结果,成本稍高一些,但是功能也更完备一些,不仅能可以进行静态检查,也可以进行必要的自动化测试;

而本次主要介绍的就是基于 Pre-commit 进行必要的代码检查与格式化,期间遇到一些问题,整理出来帮助后人少踩坑吧。

Pre-commit 简单介绍

Pre commit 是 git 提供的预提交机制,可以在创建 commit 之前执行预定义的钩子程序,从而方便执行必要的代码检查。

而在实践中可能会需要执行大量的钩子程序,如果来管理这些钩子程序呢,Pre-commit 就是其中一个应用较多的框架,通过这个框架可以比较方便地管理大量的预提交钩子程序,这样简化了维护成本。如何来使用 Pre-commit 框架呢?

  1. 安装 Pre-commit 框架,一般情况下 pip 安装下即可;
  2. 在工程中添加 .pre-commit-config.yaml 文件,需要安装的钩子程序都是维护在这个配置文件中的;
  3. 通过 pre-commit install 安装对应的钩子程序;

后续在创建 commit 时就会依次执行安装好的钩子程序,如果不符合钩子程序对应的规范,就会检查失败,commit 无法创建,类似如下所示:
请添加图片描述

Pre-commit 的使用主要关注的是配置文件 .pre-commit-config.yaml 的定义,配置文件的一个简单例子如下所示:

repos:
-   repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.3.0
    hooks:
    -   id: check-yaml
    -   id: end-of-file-fixer
    -   id: trailing-whitespace

-   repo: https://github.com/psf/black
    rev: 22.10.0
    hooks:
    -   id: black

在配置文件中主要关注下面的字段:

  • repo:指定钩子对应的代码库
  • rev:指定代码仓库对应的版本
  • hooks:指定代码库中需要用到的钩子

Pre-commit 支持的完整的所有的代码仓库与对应的钩子见官方 Supported Hooks

具体实践

项目中使用的是 yapf + isort + mypy 的组合,之前已经在工程中安装完成,包管理是使用 poetry 实现的,因此格式化工具对应的配置都是定义在 poetry.yaml 文件中的。本次使用 Pre-commit 期望也能直接使用原有格式化工具的配置,从而保证与定义好的规范保持一致。

yapf

本次在 Pre-commit 中使用 yapf 时,配置文件 .pre-commit-config.yaml 中的定义如下所示:

- repo: https://github.com/google/yapf
  rev: 'v0.31.0'
  hooks:
    - id: yapf

在 Pre-commit 中使用 yapf 时,报错 toml package is needed for using pyproject.toml as a configuration file,但是直接调用 yapf 时可以正常执行的。

定位问题后发现,Pre-commit 安装的钩子是放在独立的虚拟环境里面的,这个虚拟环境中没有对应的 toml 包,因此执行 yapf 报错

解决方案就是通过 additional_dependencies 指定对应的包依赖,这样依赖的包才能被正确安装,修改配置后即可正确执行,最终配置如下:

- repo: https://github.com/google/yapf
  rev: 'v0.31.0'
  hooks:
    - id: yapf
      additional_dependencies: [toml]
isort

isort 主要用于进行代码 import 顺序的调整,定义的配置如下所示:

- repo: https://github.com/PyCQA/isort
  rev: 5.12.0
  hooks:
    - id: isort
mypy

项目中主要是使用 mypy 进行静态的代码检查,初始定义的配置如下所示:

- repo: https://github.com/pre-commit/mirrors-mypy
  rev: 'v0.910'
  hooks:
  -   id: mypy

增加测试代码进行验证后发现问题很多:

  1. Pre-commit 中使用的 mypy 虽然是增量提交的,但是很多没有修改的文件中的问题也被提醒出来,导致需要修改的文件特别多;
  2. 原本在 pyproject.toml 中 mypy 配置中明确排除掉的文件中的问题也会上报出来,而手工执行 mypy 是被正常忽略的;

对于问题 1 定位后发现 mypy 增量提交时会递归对 import 导入的文件同时进行静态类型检查,从静态类型工具的角度是可以理解的,因为需要确认调用方和定义的函数类型是否一致,因此需要递归导入和检查,但是这样就会导致增量提交失去意义,对于已有工程而言在发起新提交时会需要修改大量的文件。

问题 2 的原因其实也与这个 import 循环导入有关,mypy 配置时通过 exclude 参数排除掉文件,在 mypy 全量检查时会跳过,但是如果是增量提交,通过 import 导入的文件依旧会执行静态类型检查,此时 exclude 就没办法排除掉了

对于提到的这两个问题,github 上有不少人给 mypy 上报了异常,甚至原有 exclude 参数不能排除掉 import 文件的机制设计,有开发者提出了 force exclude 的 PR,但是截止目前而言,这个想法没有被现有 mypy 的维护者认可

从 mypy 维护者的解释来看,mypy 作为静态类型检查工具,是需要结合执行上下文来尽可能发现不符合静态类型定义的问题,force exclude 会导致没办法根据调用上下文发现类型不匹配的问题,mypy 就失去了意义。从 mypy 作为静态类型检查工具的角度来看,这个解释没有太大问题,但是在 Pre-commit 中使用 mypy 确实就会出现上面所说的那些问题,导致根本不可用。因此 mypy 维护者提出了 建议解决方案,方案的解决思路如下:

  1. mypy 开启对整个工程的代码检查,即传递参数 pass_filenames: false,不要使用增量式传递新增文件的方式;
  2. pre-commit 使用独立的虚拟环境去安装 mypy,会导致第三方库的类型检查失效,建议直接使用原有运行虚拟环境中的 mypy 进行检查,通过 language: system 进行配置;

最终配置定义如下:

- repo: https://github.com/pre-commit/mirrors-mypy
  rev: 'v0.910'
  hooks:
  - id: mypy
    entry: mypy .
    language: system
    pass_filenames: false

测试确实能解决掉原先 exclude 不生效的问题,但是由于目前是全量检查,因此需要先对工程中原有的不符合 mypy 规范的进行了修复后,再开启对应的 mypy 检查。虽然解决方案不够完美,需要先进行一轮全局的修复,但是修复后工作良好。

总结

通过上面的配置调整,最终在工程中正常配置了 Pre-commit,保证了团队代码风格的一致性,Pre-commit 通过将必要的规范限制在开发环境,保证了对开发人员的统一风格约束,从而提升整体代码质量,有兴趣可以尝试一下

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1703290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java毕业设计 基于springboot vue考勤管理系统

Java毕业设计 基于springboot vue考勤管理系统 SpringBoot 考勤管理系统 功能介绍 员工 登录 个人中心 修改密码 个人信息 员工请假管理 员工出差管理 薪资管理 员工签到管理 公告管理 管理员 登录 个人中心 修改密码 个人信息 员工管理 员工请假管理 员工出差管理 薪资管理…

Linux修炼之路之自动化构建工具,进度条,gdb调试器

目录 一:自动化构建工具make/makefile 生成内容: 清理内容: 对于多过程的: 对于多次make: 特殊符号: 二:小程序之进度条 三:git的简单介绍 四:Linux调试器gdb 接…

2024年蓝桥杯B组C++——复盘

1、握手问题 知识点:模拟 这道题很简单。但是不知道考试的时候有没有写错。一开始的43个人握手,仅需要两两握手,也就是从42个握手开始,而非43.很可惜。这道题没有拿稳这5分。也很有可能是这5分导致没有进决赛。 总结&#xff1a…

调用萨姆索诺夫函数:深入探索函数的参数与返回值

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、萨姆索诺夫函数的引入与调用 二、如何获取函数的返回值 三、无参数与无返回值的函数调…

06_Tomcat

文章目录 Tomcat1.概念2.Tomcat安装3.Tomcat项目结构4.标准web项目结构5.Tomcat部署项目方式6.IDEA关联Tomcat6.1 构建tomcat和idea关联6.2 使用idea创建一个Javaweb工程6.3 使用idea将工程**构建**成一个app6.4 使用idea将构建好的app**部署**到tomcat中 Tomcat 1.概念 Tomc…

《浪姐》也搞live直播,真成综艺流量密码了?

继《歌手》之后,芒果的另一档综艺《浪姐》也将开启直播。 《乘风2024》官博宣布进行突击加场直播赛,姐姐们将面临全开麦live直播,摇人投票排在前十的姐姐获得live直播抢先权。 这是看《歌手2024》直播赛制火了,也想蹭个热度搞直…

拓展海外市场,助力中国海外运营企业实现全球化发展——工博科技SAP出海数字化解决方案

近年来,在全球化浪潮下,中国出海企业正从简单的产品扩张向更加成熟的跨国经营及全球化发展转变。中资企业要积极拓展国际市场、加大步伐融入全球的生态,打造韧性供应链,但面对风云变幻的国际形势,需要提高自身的风险管…

Java绩效考核系统源码 springboot员工绩效考核系统源码

Java绩效考核系统源码 springboot员工绩效考核系统源码-009 源码下载地址:https://download.csdn.net/download/xiaohua1992/89352195 项目介绍 本系统的功能分为管理员和员工两个角色 管理员的功能有: (1)个人中心管理功能&a…

基于Pytorch框架的深度学习ShufflenetV2神经网络十七种猴子动物识别分类系统源码

第一步:准备数据 17种猴子动物数据: self.class_indict ["白头卷尾猴", "弥猴", "山魈", "松鼠猴", "叶猴", "银色绒猴", "印度乌叶猴", "疣猴", "侏绒"…

DDR、LPDDR和GDDR的区别

1、概况 以DDR开头的内存适用于服务器、云计算、网络、笔记本电脑、台式机和消费类应用,支持更宽的通道宽度、更高的密度和不同的形状尺寸。 以LPDDR开头的内存适合面向移动和汽车这些对规格和功耗非常敏感的领域,提供更窄的通道宽度和多种低功耗运行状态…

node.js学习P3-P10

P3 npm package.json(package解读npm工具换镜像源) 一个package.json文件可以的作用 作为一个描述文件,描述了你的项目依赖哪些包 ,用来干什么的允许我们使用“语义版本规则”,指明你项目依赖的版本让你的构建更好的…

cin-getline缓存区

更多资源请关注纽扣编程微信公众号 cin.sync()清除缓存区 如果需要输入如下内容 3 This is C language. This is JAVA language. This is Python language. 写如下程序 #include<bits/stdc.h> using namespace std; string str[100]; int main(){int n;cin>&…

【Pandas】配合Numpy做数据异常值处理

1.四分卫间距确定数据范围 numpy.quantile(a, q, axisNone, outNone, overwrite_inputFalse, methodlinear, keepdimsFalse, *, interpolationNone)[source]计算指定轴的n分位数 参数q给定指定的几分位数&#xff0c;范围[0,1] import numpy as np import pandas as pd def …

每日一题——Python实现PAT甲级1029 Median(举一反三+思想解读+逐步优化)

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的方法 代码功能和结构点评 时间复杂度分析 空间复杂度分析 优化建议 我要更强…

【Text2SQL 论文】IncSQL:通过增量式生成 action 序列来得到 SQL

论文&#xff1a;IncSQL: Training Incremental Text-to-SQL Parsers with Non-Deterministic Oracles ⭐⭐⭐ ICLR 2019&#xff0c;arXiv:1809.05054, Microsoft Research 一、论文速读 本文提出了 IncSQL&#xff0c;一个使用 Non-Deterministic Oracles 思路的增量式 Text…

从零开始打造教育APP:在线教育系统源码与开发流程

很多人疑问&#xff0c;应该如何从零开始打造一个在线教育APP&#xff1f;今天&#xff0c;小编将详细为大家讲解在线教育系统的源码与开发流程。 一、需求分析 对于在线教育APP&#xff0c;需要要明确以下几点&#xff1a; 1.目标用户&#xff1a;明确APP的用户群体&#xf…

字符串和字符串函数(1)

前言&#xff1a; 字符串在C语言中比较特别&#xff0c;没有单另的字符串类型&#xff0c;想要初始化字符串必须用字符变量的数组初始化&#xff0c;但是在C语言标准库函数中提供了大量能对字符串进行修改的函数&#xff0c;比如说可以实现字符串的的拷贝&#xff0c;字符串的追…

判断dom元素是否滚动到底、是否在可视区域

概览 我们日常开发中&#xff0c;在面对懒加载、虚拟列表需求时&#xff0c;经常需要判断dom元素是否滚动到底、是否在可视区域。但是由于涉及的属性太多了&#xff0c;比如scrollTop、clientHeight、scrollHeight、getBoundingClientRect()等属性&#xff0c;现根据这两个场景…

Docker环境安装并使用Elasticsearch

1、拉取es docker pull elasticsearch:7.10.12、查看镜像 docker images3、启动es docker run -d --name esearch -p 9200:9200 -p 9300:9300 elasticsearch:7.10.14、如果启动ES时出现一下问题 Unable to find image docker.elastic.co/elasticsearch/elasticsearch:7.10.…

基于springboot+vue的班级综合测评管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…