|测试状态| |分析状态| |CodeQL状态| |覆盖率| |PyPI版本| |距上次发布的提交数| |下载量| |CII最佳实践|
.. |PyPI版本| image:: https://badge.fury.io/py/vermin.svg :target: https://pypi.python.org/pypi/vermin/
.. |测试状态| image:: https://github.com/netromdk/vermin/workflows/Test/badge.svg?branch=master :target: https://github.com/netromdk/vermin/actions
.. |分析状态| image:: https://github.com/netromdk/vermin/workflows/Analyze/badge.svg?branch=master :target: https://github.com/netromdk/vermin/actions
.. |CodeQL状态| image:: https://github.com/netromdk/vermin/workflows/CodeQL/badge.svg?branch=master :target: https://github.com/netromdk/vermin/security/code-scanning
.. |Snyk状态| image:: https://github.com/netromdk/vermin/workflows/Snyk%20Schedule/badge.svg?branch=master :target: https://github.com/netromdk/vermin/actions
.. |覆盖率| image:: https://coveralls.io/repos/github/netromdk/vermin/badge.svg?branch=master :target: https://coveralls.io/github/netromdk/vermin?branch=master
.. |距上次发布的提交数| image:: https://img.shields.io/github/commits-since/netromdk/vermin/latest.svg
.. |下载量| image:: https://static.pepy.tech/personalized-badge/vermin?period=total&units=international_system&left_color=gray&right_color=blue&left_text=Downloads :target: https://pepy.tech/project/vermin
.. |CII最佳实践| image:: https://bestpractices.coreinfrastructure.org/projects/6451/badge :target: https://bestpractices.coreinfrastructure.org/projects/6451
Vermin
并发检测运行代码所需的最低Python版本。此外,由于代码是纯Python编写的,没有任何外部依赖,它可以在Python 3+上运行,但仍然包括对Python 2.x功能的检测。
它通过将Python代码解析为抽象语法树(AST)来工作,遍历AST并与内部字典进行匹配。内部字典包含了3796条规则,涵盖了Python 2.0-2.7和3.0-3.12版本,分为178个模块,2614个模块成员(类/函数/常量),875个函数关键字参数,4个strftime指令,3个bytes格式指令,2个array类型代码,3个codecs错误处理器名称,20个codecs编码,78个内置泛型注解类型,9个内置字典联合(|
)类型,8个内置字典联合合并(|=
)类型,以及2个用户函数装饰器。
可以启用标准库的向后兼容版本(如typing
)以获得更好的结果。通过--help
可以获取完整的向后兼容列表。
该项目经过了充分测试,包含4008个单元和集成测试,在Linux、macOS和Windows上执行。
建议使用最新的Python版本来运行Vermin,因为它使用Python自带的语言解析器来检测语言特性,如Python 3.6引入的f-strings等。
目录
使用方法 <#使用方法>
__特性 <#特性>
__注意事项 <#注意事项>
__配置文件 <#配置文件>
__示例 <#示例>
__代码检查(仅显示目标版本违规) <#代码检查仅显示目标版本违规>
__API(实验性) <#api实验性>
__分析排除 <#分析排除>
__可解析输出 <#可解析输出>
__贡献 <#贡献>
__
使用方法
使用Vermin非常简单。
从代码仓库中直接运行或通过特定解释器运行::
% ./vermin.py /path/to/your/project # (1) 通过/usr/bin/env python
执行
% python3 vermin.py /path/to/your/project # (2) 特定使用python3
或者通过PyPi <https://pypi.python.org/pypi/vermin/>
__安装::
% pip install vermin % vermin /path/to/your/project
Homebrew <https://brew.sh>
__ (包 <https://formulae.brew.sh/formula/vermin#default>
__)::
% brew install vermin
Spack <https://spack.io>
__ (包 <https://github.com/spack/spack/blob/develop/var/spack/repos/builtin/packages/py-vermin/package.py>
__)::
% git clone https://github.com/spack/spack.git % . spack/share/spack/setup-env.sh # 根据使用的shell而定 % spack install py-vermin % spack load py-vermin
Arch Linux (AUR) <https://aur.archlinux.org/packages/python-vermin/>
__::
% yay -S python-vermin
在使用持续集成(CI)工具(如Travis CI <https://travis-ci.org/>
_)时,可以使用Vermin来检查所需的最低版本是否发生变化。以下是一个示例::
install:
- ./setup_virtual_env.sh
- pip install vermin script:
- vermin -t=2.7 -t=3 project_package otherfile.py
Vermin也可以作为pre-commit <https://pre-commit.com/>
__钩子使用:
.. code-block:: yaml repos: - repo: https://github.com/netromdk/vermin rev: GIT_SHA_OR_TAG # 例如:'e88bda9' 或 'v1.3.4' hooks: - id: vermin # 在此指定你的目标版本,或者像往常一样在 Vermin 配置文件中指定: args: ['-t=3.8-', '--violations'] # (如果你的目标版本在 Vermin 配置文件中指定,你可以完全省略 'args' 条目)
使用钩子时,必须通过包中的 Vermin 配置文件或通过 .pre-commit-config.yaml 配置中的 args 选项指定目标版本。如果你通过 args 传递目标版本,建议也包含 --violations(如上所示)。
如果你使用 vermin-all 钩子,你可以像往常一样指定任何目标版本。但是,如果你使用 vermin 钩子,你的目标版本必须采用 x.y- 的形式(而不是 x.y),否则当你的暂存更改满足低于你的目标版本的最低版本时,你会遇到问题。
有关如何在项目中设置钩子的更多一般信息,请参阅 pre-commit 文档。
功能
检测到的功能包括 v2/v3 的 print expr 和 print(expr)、long、f-字符串、协程(async 和 await)、异步生成器(在同一函数中使用 await 和 yield)、异步推导式、推导式中的 await、异步 for 循环、布尔常量、命名表达式、仅关键字参数、仅位置参数、nonlocal、yield from、异常上下文原因(raise .. from ..)、except*、set 字面量、set 推导式、dict 推导式、中缀矩阵乘法、"..".format(..)、导入(import X、from X import Y、from X import *)、函数调用(关于名称和关键字参数)、使用的 strftime + strptime 指令、函数和变量注解(包括 Final 和 Literal)、finally 块中的 continue、模逆 pow()、数组类型码、编解码器错误处理名称、编码、bytes 和 bytearray 的 % 格式化和指令、with 语句、异步 with 语句、with 语句中的多个上下文表达式、with 语句中用括号分组的多个上下文表达式、解包赋值、广义解包、切片外的省略号字面量(...)、字典联合({..} | {..})、字典联合合并(a = {..}; a |= {..})、内置泛型类型注解(list[str])、函数装饰器、类装饰器、宽松装饰器、metaclass 类关键字、使用 match 的模式匹配、以 X | Y 形式编写的联合类型,以及类型别名语句(type X = SomeType)。它试图检测并忽略与库定义的符号名称冲突的用户自定义函数、类、参数和变量。
注意事项
有关常见问题,请查看 FAQ 讨论。
默认情况下,自文档 f-字符串检测已被禁用,因为内置 AST 无法区分 f'{a=}' 和 f'a={a}',例如,它优化掉了一些信息(#39)。这会错误地将一些只使用普通 f-字符串的源代码标记为使用自文档 f-字符串。要启用(不稳定的)f-字符串自文档检测,请使用 --feature fstring-self-doc。
检测联合类型(X | Y PEP 604)可能很棘手,因为 Vermin 在解析和遍历 AST 时不知道常量和类型的所有底层细节。因此,使用了启发式方法,有时可能会产生不正确的结果(#103)。要启用(不稳定的)联合类型检测,请使用 --feature union-types。
当使用 from future import annotations 时,函数和变量注解不会在定义时评估(PEP 563)。这就是为什么默认启用 --no-eval-annotations 的原因(自 v1.1.1 起,#66)。如果注解在运行时被评估,比如使用 typing.get_type_hints 或评估对象的 annotations,应该使用 --eval-annotations 以获得最佳结果。
配置文件
Vermin 自动尝试检测配置文件,从运行它的当前工作目录开始,沿父文件夹向上查找,直到达到根目录或项目边界文件/文件夹。但是,如果指定了 --config-file,则不会自动检测和加载配置。
正在查找的配置文件名:vermin.ini、vermin.conf、.vermin、setup.cfg
项目边界文件/文件夹:.git、.svn、.hg、.bzr、_darcs、.fslckout、.p4root、.pijul
可以在这里找到一个示例配置文件。
请注意,Vermin 配置可以与其他配置位于同一 INI 文件中,比如常用的 setup.cfg:
.. code-block:: ini [vermin] verbose = 1 processes = 4
[flake8] ignore = E111,F821
示例
.. code-block:: console
% ./vermin.py vermin 最低所需版本: 3.0 不兼容版本: 2
% ./vermin.py -t=3.3 vermin 最低所需版本: 3.0 不兼容版本: 2 未达到目标版本: 3.3 % echo $? 1
% ./vermin.py --versions vermin 最低所需版本: 3.0 不兼容版本: 2 版本范围: 2.0, 2.6, 2.7, 3.0
% ./vermin.py -v examples 正在检测Python文件.. 使用8个进程分析6个文件.. /path/to/examples/formatv2.py 2.7, 3.2 /path/to/examples/argparse.py 2.7, 3.0 /path/to/examples/formatv3.py 2.0, 3.0 /path/to/examples/printv3.py !2, 3.4 /path/to/examples/abc.py /path/to/examples/unknown.py 最低所需版本: 3.4 不兼容版本: 2
% ./vermin.py -vv /path/to/examples/abc.py 正在检测Python文件.. 使用8个进程分析.. !2, 3.4 /path/to/examples/abc.py 'abc' 需要 2.6, 3.0 'abc.ABC' 需要 !2, 3.4
最低所需版本: 3.4 不兼容版本: 2
% ./vermin.py -vvv /path/to/examples/abc.py 正在检测Python文件.. 使用8个进程分析.. !2, 3.4 /path/to/examples/abc.py 第1行第7列: 'abc' 需要 2.6, 3.0 第2行: 'abc.ABC' 需要 !2, 3.4
最低所需版本: 3.4 不兼容版本: 2
% ./vermin.py -f parsable /path/to/examples/abc.py /path/to/examples/abc.py:1:7:2.6:3.0:'abc' 模块 /path/to/examples/abc.py:2::!2:3.4:'abc.ABC' 成员 /path/to/examples/abc.py:::!2:3.4: :::!2:3.4:
有关可解析输出格式的更多信息,请参阅 可解析输出 <#parsable-output>
__。
代码检查:仅显示目标版本违规情况
Vermin在正常运行时会显示许多有用的最低版本结果,但它也可以作为一个代码检查工具,仅显示违反指定目标版本的规则。这可以通过使用 --violations
(或 --lint
) 和一个或两个 --target
值来实现。当仅显示违规情况时,会自动设置详细级别2,但可以根据需要增加。最终的版本判断结果仍会在最后计算并打印出来,程序退出代码表示是否满足指定的目标(0
)或违反(1
)。但是,如果没有触发任何规则,由于结果不确定,退出代码将为 0
。
.. code-block:: console
% cat test.py import argparse # 2.7, 3.2 all() # 2.5, 3.0 enumerate() # 2.3, 3.0
% ./vermin.py -t=2.4- -t=3 --violations test.py ; echo $? 正在检测Python文件.. 使用8个进程分析.. 2.7, 3.2 test.py 'all' 成员需要 2.5, 3.0 'argparse' 模块需要 2.7, 3.2
最低所需版本: 2.7, 3.2 未达到目标版本: 2.4-, 3.0 1
前两行违反了目标版本要求,但第三行符合要求,因此不会显示。
API(实验性)
最低版本、使用的功能结构等信息也可以通过 vermin
Python模块以编程方式访问,尽管这是一个实验性功能。仍建议使用命令行界面。
.. code-block:: python
import vermin as V V.version_strings(V.detect("a = long(1)")) '2.0, !3'
config = V.Config() config.add_exclusion("long") V.version_strings(V.detect("a = long(1)", config)) '~2, ~3'
config.set_verbose(3) v = V.visit("""from argparse import ArgumentParser ... ap = ArgumentParser(allow_abbrev=True) ... """, config) print(v.output_text(), end="") 第1行第5列: 'argparse' 模块需要 2.7, 3.2 第2行: 'argparse.ArgumentParser(allow_abbrev)' 需要 !2, 3.5 V.version_strings(v.minimum_versions()) '!2, 3.5'
分析排除项
在某些情况下,可能需要进行分析排除。可以使用参数 --exclude <name>
(可指定多个)来通过名称排除模块、成员、kwargs、编解码器错误处理程序名称或编解码器编码的分析。考虑以下代码块,它检查 PROTOCOL_TLS
是否是 ssl
的属性:
import ssl
tls_version = ssl.PROTOCOL_TLSv1
if hasattr(ssl, "PROTOCOL_TLS"):
tls_version = ssl.PROTOCOL_TLS
它会显示 "'ssl.PROTOCOL_TLS' 需要 2.7, 3.6",但要从结果中排除这个,可以使用 --exclude 'ssl.PROTOCOL_TLS'
。之后,只会显示 "'ssl' 需要 2.6, 3.0",最终所需的最低版本是 v2.6 和 v3.0,而不是 v2.7 和 v3.6。
甚至可以使用行级别的 # novermin
或 # novm
注释在更精细的级别上排除代码。以下代码产生与前一个代码块相同的行为,但仅适用于特定的 if
及其主体:
import ssl
tls_version = ssl.PROTOCOL_TLSv1
if hasattr(ssl, "PROTOCOL_TLS"): # novermin
tls_version = ssl.PROTOCOL_TLS
在使用多个工具进行各种功能的注释的情况下,可以通过为每个注释"段"使用 #
来定义排除:
if hasattr(ssl, "PROTOCOL_TLS"): # noqa # novermin # pylint: disable=no-member
tls_version = ssl.PROTOCOL_TLS
请注意,如果代码库中没有任何 # novermin
或 # novm
的出现,使用 --no-parse-comments
参数或 parse_comments = no
配置设置可以实现高达 30-40%+ 的加速。
可解析输出
在需要 Vermin 输出结果的场景中,建议使用可解析的输出格式(--format parsable
)而不是默认输出。启用此格式后,每行将采用以下形式:
<file>:<line>:<column>:<py2>:<py3>:<feature>
只有当详细程度级别足够高时,才会显示 <line>
和 <column>
,否则它们为空。
每个处理文件中检测到的每个特性都将在单独的行上定义 <feature>
。处理文件的最后一行将有一个特殊行,包含相应的 <file>
但没有 <feature>
,构成该文件的最低版本:
<file>:::<py2>:<py3>:
最后一行是整个扫描的最终最低版本结果,因此没有 <file>
和 <feature>
:
:::<py2>:<py3>:
示例输出检查
% ./vermin.py -f parsable /path/to/project
/path/to/project/abc.py:1:7:2.6:3.0:'abc' 模块
/path/to/project/abc.py:2::!2:3.4:'abc.ABC' 成员
/path/to/project/abc.py:::!2:3.4:
/path/to/project/except_star.py:::~2:~3:
/path/to/project/annotations.py:::2.0:3.0:print(expr)
/path/to/project/annotations.py:1::!2:3.0:注解
/path/to/project/annotations.py:::!2:3.0:
:::!2:3.4:
abc.py
通过以下方式需要 !2
和 3.4
:
/path/to/project/abc.py:::!2:3.4:
except_star.py
通过以下方式需要 ~2
和 ~3
:
/path/to/project/except_star.py:::~2:~3:
而 annotations.py
通过以下方式需要 !2
和 3.0
:
/path/to/project/annotations.py:::!2:3.0:
这意味着最终结果是 !2
和 3.4
,这在最后一行显示:
:::!2:3.4:
贡献
非常欢迎贡献,特别是添加和更新模块、函数、类等的检测规则,以涵盖尽可能多的 Python 版本。有关更多信息,请参阅 CONTRIBUTING.md
。