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

背景信息

统一代码风格首先需要定义参照的规范,每个团队可能会有自己的规范,我们选择的规范是 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-hooksrev: v2.3.0hooks:-   id: check-yaml-   id: end-of-file-fixer-   id: trailing-whitespace-   repo: https://github.com/psf/blackrev: 22.10.0hooks:-   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/yapfrev: '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/yapfrev: 'v0.31.0'hooks:- id: yapfadditional_dependencies: [toml]
isort

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

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

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

- repo: https://github.com/pre-commit/mirrors-mypyrev: '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-mypyrev: 'v0.910'hooks:- id: mypyentry: mypy .language: systempass_filenames: false

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

总结

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

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

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

相关文章

bootstrap实现天平效果

之前提到了,最近,孩子的幼儿园让家长体验“半日助教活动”,每个家长需要讲授15-20分钟的课程。作为一名程序员,实在没有能教的课程,只能做了一个小游戏,带着小朋友们熟悉数字。 在上一章博客中&#xff0c…

【读书】读书笔记——理科生的视角:底层逻辑+数学之美

1,底层逻辑1(看清这个世界的底牌) 刘润 著 0)什么是底层逻辑? 底层逻辑是:事物之间共同点、变化背后不变的东西事;看清事物的本质,才能在复杂变化中从根本上解决问题。 1&#x…

【Java继承】(超级详细!!!)

【Java继承】(超级详细!!!) 1、 继承的概念2 、继承的语法3、 父类成员访问3.1 子类中访问父类的成员变量3.2 子类中访问父类的成员方法 4、 super关键字5 、子类的构造方法6、 继承关系上的执行顺序7、protected 关键…

选项卡式小部件QTabWidget

文章目录 1. 详细介绍2. 常用属性3. 信号4. 常用函数5. 官方示例Tab Dialog QTabWidget提供一堆选项卡式小部件。 1. 详细介绍 选项卡式部件提供一个选项卡栏和一个用于显示与每个选项卡相关的页面的页面区域。 默认情况下,选项卡栏显示在页面区域上方,…

Vue.js - 计算属性与侦听器 【0基础向 Vue 基础学习】

文章目录 计算属性 computedcomputed 的使用方法computed 与 method 的区别计算属性完整写法 watch 侦听器(监视器)简单写法 → 简单类型数据,直接监视完整写法 → 添加额外配置项 计算属性 computed computed 的使用方法 **概念&#xff1…

web题解,基础知识巩固(qsnctf)

1.文章管理系统 1)打开题目,把它页面翻完了,没看懂它有啥用 2)看了看源码,也是一样的,没找到有用的东西 3)想着可能还是在隐藏文件里找,那我就直接用dirsearch扫扫看 4)…

初识C++ · 模拟实现vector

目录 前言: 1 部分简单函数的实现 2 push_back和pop_back 3 reserve和resize 4 Print_vector 5 insert和erase 6 拷贝构造 7 构造 8 赋值 9 memcpy的问题 10 迭代器失效 前言: 继上文模拟实现了string之后,接着就模拟实现vector&…

MyBatis复习笔记

3.Mybatis复习 3.1 xml配置 properties&#xff1a;加载配置文件 settings&#xff1a;设置驼峰映射 <settings><setting name"mapUnderscoreToCamelCase" value"true"/> </settings>typeAliases&#xff1a;类型别名设置 #这样在映射…

如何去除视频上的文字?免费无痕去水印分享!视频制作良器!

对于需要进行二次创作的视频素材&#xff0c;去除原有的文字可以提供一个更加干净的画布&#xff0c;方便创作者在其基础上进行新的创作和编辑。同时&#xff0c;去除文字后的视频也更方便分享到各种平台&#xff0c;避免因为平台对文字的限制而导致视频无法发布或传播。 要去除…

云计算期末复习(1)

云计算基础 作业&#xff08;问答题&#xff09; &#xff08;1&#xff09;总结云计算的特点。 透明的云端计算服务 “无限”多的计算资源&#xff0c;提供强大的计算能力 按需分配&#xff0c;弹性伸缩&#xff0c;取用方便&#xff0c;成本低廉资源共享&#xff0c;降低企…

Windows操作系统基本知识整理

目录 引言 一、Windows操作系统的发展历史 1.1 Windows 1.0到Windows 3.0 1.2 Windows 95到Windows Me 1.3 Windows NT到Windows 2000 1.4 Windows XP到Windows 7 1.5 Windows 8到Windows 10 二、Windows操作系统的核心组件 2.1 内核 2.2 文件系统 2.3 图形用户界面&…

内网横向移动小补充 --->PTK

大家别急&#xff0c;我的基于资源的约束性委派攻击还在写&#xff0c;这个东西一时半会讲不清楚&#xff0c;所以我在这里先来补充一点横向移动以前没说好的东西&#xff01;&#xff01;&#xff01; 在更啦&#xff0c;别催啦~~~~ 还记得我之前在内网渗透里面讲过这个PTK&a…

亚马逊云主管马特·加尔曼面临压力,致力于在人工智能领域赶超竞争对手

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

mysql中连接查询的成本

大家好。上篇文章我们讲了mysql中成本的含义以及单表查询如何计算成本。现在我们接着讲讲mysql中连接查询的成本。 在讲之前&#xff0c;我们先创建两张一样的表single_table和single_table2&#xff0c;并在表中插入10000条数据。在下面的讲解中&#xff0c;我们称single_tab…

java并发工具类都有哪些

Java中的并发工具类包括&#xff1a; CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成某些操作。它通常用于线程间的同步&#xff0c;例如在一个线程完成其工作后通知其他线程继续执行。 CyclicBarrier CyclicBarrier是一个同步辅助类&#xff0c;它允许一…

【面试必看】Java并发

并发 1. 线程 1. 线程vs进程 进程是程序的一次执行过程&#xff0c;是系统运行程序的基本单位&#xff0c;因此进程是动态的。 系统运行一个程序即是一个进程从创建&#xff0c;运行到消亡的过程。在 Java 中&#xff0c;当我们启动 main 函数时其实就是启动了一个 JVM 的进…

ChaosMeta V0.7.0 版本发布 进入CNCF混沌工程全景图

混沌工程 ChaosMeta 的全新版本 V0.7.0 现已正式发布&#xff01;该版本包含了许多新特性和增强功能&#xff0c;在编排界面提供了多集群管理&#xff0c;在代码层面支持多命令下发通道的选择。另外由蚂蚁集团发起的ChaosMeta于北京时间2024年1月10日正式进入CNCF混沌工程全景图…

07_Servlet

Servlet 一 Servlet简介 1.1 动态资源和静态资源 静态资源 无需在程序运行时通过代码运行生成的资源,在程序运行之前就写好的资源. 例如:html css js img ,音频文件和视频文件 动态资源 需要在程序运行时通过代码运行生成的资源,在程序运行之前无法确定的数据,运行时动态生成…

转行一年了

关注、星标公众号&#xff0c;直达精彩内容 ID&#xff1a;技术让梦想更伟大 整理&#xff1a;李肖遥 来公司一年了。 说是转行其实还是在半导体行业&#xff0c;熟悉我的朋友知道 &#xff0c;我在18年开始进入半导体行业&#xff0c;那个时候想着行业很重要&#xff0c;站对了…

气泡水位计的安装方法详解(二)

气泡水位计的安装方法详解&#xff08;二&#xff09; 产品简介 气泡式水位计ZL-BWL-013是一款适用于水文、水利信息化建设领域的新一代水位测量类设备&#xff0c;产品执行GB/T 11828.2-2022标准。ZL-BWL-013气泡水位计&#xff0c;具有安装方便、易于操作&#xff0c;高精度…