当前位置: 首页 > 工具软件 > Pylint > 使用案例 >

Pylint静态代码检查使用指南

松铭
2023-12-01

前言

初学编码标准?
Pylint可以作为您的向导,揭示幕后真正发生了什么,并帮助您成为一名更有见识的程序员。

如果人们发现你的代码难以使用或理解,你的良好意图可能不会得到预期的结果。Python社区已经正式确定了一些推荐的编程风格,以帮助每个人以一种对共享代码最有意义的共同的、商定的风格编写代码。这种风格在PEP 8中被捕获,即“Python代码的风格指南”。:Pylint是一种快速而简单的方法,可以查看您的代码是否捕获了PEP 8的精髓,因此对其他潜在用户是友好的。

简单一句话就是Pylint可以让你的代码写的更规范,漂亮,可读性高。

入门指南

安装pylint

很简单,直接pip安装:

$ pip install pylint 

直接运行pylint会输出一个简单的帮助列表,以下是我们要关注的几个选项:

Commands:
  --help-msg=<msg-id>
  --generate-rcfile
Messages control:
  --disable=<msg-ids>
Reports:
  --reports=<y_or_n>
  --output-format=<format>

如果你需要更多的细节,你也可以要求更长的帮助信息,比如:

$ pylint --long-help
...
输出更多的帮助信息
...

请注意这个较长的帮助输出的最后一点。这给了你一个提示,Pylint将选择什么:

Output:
   Using the default text output, the message format is :
  MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE
  There are 5 kind of message types :
  * (C) convention, for programming standard violation
  * (R) refactor, for bad code smell
  * (W) warning, for python specific problems
  * (E) error, for probable bugs in the code
  * (F) fatal, if an error occurred which prevented pylint from doing
  further processing.

你的第一个Pylint操作

我们将使用一个基本的Python脚本作为教程的素材。我们将使用的起始代码名为simplecaesar.py,完整的代码如下:

#!/usr/bin/env python3

import string;

shift = 3
choice = input("would you like to encode or decode?")
word = input("Please enter text")
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
    for letter in word:
        if letter == ' ':
            encoded = encoded + ' '
        else:
            x = letters.index(letter) + shift
            encoded = encoded + letters[x]
if choice == "decode":
    for letter in word:
        if letter == ' ':
            encoded = encoded + ' '
        else:
            x = letters.index(letter) - shift
            encoded = encoded + letters[x]

print(encoded)

让我们开始。
如果我们运行这个:

$ pylint simplecaesar.py
************* Module simplecaesar
simplecaesar.py:3:0: W0301: Unnecessary semicolon (unnecessary-semicolon)
simplecaesar.py:1:0: C0114: Missing module docstring (missing-module-docstring)
simplecaesar.py:5:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
simplecaesar.py:9:0: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
simplecaesar.py:13:12: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)

-----------------------------------
Your code has been rated at 7.37/10

我们以上面输出的第二行为例,关注一下上面输出的第二行:

"simplecaesar.py:1:0: C0114: Missing module docstring (missing-module-docstring)"

这主要的意味是第1行违反了代码规约C0114。它告诉我,我应该有一个文档字符串。我同意,但如果我不完全明白我违反了什么代码规约规则呢。如果我是个新手,只知道我违反了惯例也没什么用。这里的另一个信息是在括号之间的消息符号missing-module-docstring。
如果我想了解更多,我可以回到命令行并尝试如下:

$ pylint --help-msg=missing-module-docstring
:missing-module-docstring (C0114): *Missing module docstring*
  Used when a module has no docstring.Empty modules do not require a docstring.
  This message belongs to the basic checker.

上边给出了关于消息符号missing-module-docstring更详细的描述。

下一步

现在我们已经完成了一些配置,让我们看看如何处理剩下的警告。
如果我们添加一个文档字符串来描述代码要做什么,将会有所帮助。然后,我在import行末尾添加了一个不必要的分号,所以我也将修复这个问题。我们稍后会介绍invalid-name消息。总之,我将在第2行添加一个文档字符串,并删除第三行结尾的分号“;”。
以下是更新后的代码:

#!/usr/bin/env python3
"""This script prompts a user to enter a message to encode or decode
using a classic Caesar shift substitution (3 letter shift)"""

import string

shift = 3
choice = input("would you like to encode or decode?")
word = input("Please enter text")
letters = string.ascii_letters + string.punctuation + string.digits
encoded = ''
if choice == "encode":
    for letter in word:
        if letter == ' ':
            encoded = encoded + ' '
        else:
            x = letters.index(letter) + shift
            encoded = encoded + letters[x]
if choice == "decode":
    for letter in word:
        if letter == ' ':
            encoded = encoded + ' '
        else:
            x = letters.index(letter) - shift
            encoded = encoded + letters[x]

print(encoded)

下面是运行它时会发生的情况:

$ pylint simplecaesar.py
************* Module simplecaesar
simplecaesar.py:7:0: C0103: Constant name "shift" doesn't conform to UPPER_CASE naming style (invalid-name)
simplecaesar.py:11:0: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)
simplecaesar.py:15:12: C0103: Constant name "encoded" doesn't conform to UPPER_CASE naming style (invalid-name)

------------------------------------------------------------------
Your code has been rated at 8.42/10 (previous run: 7.37/10, +1.05)

好了!Pylint的最后一行告诉我们,自上次运行以来,我们的代码评级提高了多少,我们只剩下invalid-name消息。

对于诸如实例变量、函数、类等的命名,有定义良好的约定。约定的重点是大写字母和小写字母的使用,以及名称中分隔多个单词的字符。这很适合通过正则表达式进行检查,因此应该匹配正则表达式(([a - z_][a - z1 -9_]*)|(__.*__))$

在这种情况下,Pylint告诉我,这些变量看起来是常量,应该都是大写的。这是Pylint从一开始就存在的内部规则。您也可以创建自己的内部命名约定,但出于本教程的目的,我们希望坚持使用PEP 8标准。在这种情况下,我声明的变量应该遵循全部小写的约定。适当的规则类似于:“should match [a-z_][a-z0-9_]{2,30}$”。注意正则表达式中的小写字母(a-z和A-Z)。

如果我们使用--const-rgx='[a-z\_][a-z0-9\_]{2,30}$'选项来运行该规则,现在它将非常安静:

$ pylint --const-rgx='[a-z_][a-z0-9_]{2,30}$' simplecaesar.py

-------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 8.42/10, +1.58)

提示:
在命令行上指定regex真的很麻烦,尤其是在我们使用许多其他选项的情况下。这时候我们可以配置Pylint来为我们存储选项,这样我们就不必在命令行中声明它们。使用配置文件是形式化规则并与他人快速共享规则的好方法。调用pylint --generate-rcfile将创建一个示例rcfile,其中设置了所有选项并附带了注释解释每个选项的含义,关于pylint怎么读取配置文件将在下面说明。

运行Pylint

Pylint应该从命令行调用,使用方式如下:

pylint [options] modules_or_packages

你应该给Pylint一个python包或模块的名称,或者指定多个包或模块。Pylint不会导入这个包或模块,但使用Python内部函数来查找它们,因此与导入包和模块遵循相同的规则和配置。您应该注意您的PYTHONPATH,因为分析模块的已安装版本而不是开发版本是一个常见错误。

也可以分析Python文件,但有一些限制。需要记住的是,Pylint将尝试将文件名转换为模块名,并且只有在成功时才能处理该文件。

pylint mymodule.py

上面的代码应该始终可以工作。因为当前工作目录是自动添加到python路径之上的,

pylint directory/mymodule.py

上面代码要运行成功,“directory”必须是一个python package(例如,有__init__.py文件或者是隐式的命名空间包)或者“directory”在python path下

命令行选项

首先,我们有两个基本的(但有用的)选项。
–version
显示pylint的版本号

-h, --help
显示命令行选项的帮助信息

Pylint是由几个检查器构筑的。你可以通过指定 --disable=<symbol>来禁用一个特定的检查器或者一些消息和消息类型,如果你只想启用某几个检查器或者消息标志,首先使用--disable=all 禁用all,然后使用--enable=<symbol>,<symbol>是一个由逗号分隔的检查器名字或者消息标志列表。有关提供的检查器及其功能的描述,请参阅可用特性列表。–disable和–enable选项可用于逗号分隔的列表,混合检查器、消息id和类别,如 -d C,W,no-error,design

每个检查器都有一些特定的选项,可以接受yes/no值、整数、python正则表达式或逗号分隔的值列表(在特殊情况下通常用于覆盖正则表达式)。要获得完整的选项列表,请使用–help

其他有用的全局选项包括:

–ignore=<file[,file…]>
Files or directories to be skipped. They should be base names, not paths.

–output-format=
Select output format (text, json, parseable,colorized,custom).

–msg-template=
Modify text output message template.

–list-msgs
Generate pylint’s messages.

–list-msgs-enabled
Display a list of what messages are enabled and disabled with the given configuration.

–full-documentation
Generate pylint’s full documentation, in reST format.

使用配置文件

前面我们已经说了,在命令行中指定太多的选项配置是很繁琐的,所以我们可以使用配置文件来指定配置,你可以使用–rcfile选项在命令行上指定配置文件,如果不指定,pylint将按照以下顺序搜索配置文件,并使用找到的第一个配置文件:

  1. pylintrc 在当前工作目录下的

  2. .pylintrc 在当前工作目录下的

  3. pyproject.toml 在当前工作目录下的, 前提是它至少有一个tool.pylint. section.

  4. setup.cfg 在当前工作目录下的, 前提是它至少有一个 pylint. section

  5. 如果当前工作目录在python包里, Pylint搜索Python包的层次结构,直到找到一个pylintrc文件. 这允许你去指定每个模块的代码标准. 当然,如果一个目录包含一个__init__.py文件,则该目录被判定为一个Python包.

  6. 由环境变量PYLINTRC命名的文件

  7. 如果你有一个不是/root的主目录:

    1. .pylintrc 在你的home目录下

    2. .config/pylintrc 在你的home目录下

  8. /etc/pylintrc

并发执行

可以加速Pylint的执行。如果正在运行的计算机有多个cpu,那么检查所有文件的工作可以通过Pylints的子进程分散到所有核上。该功能是通过-j命令行参数公开的。如果提供的数字是0,那么将自动检测和使用cpu的总数。
Example:

pylint -j 4 mymodule1.py mymodule2.py mymodule3.py mymodule4.py

这将生成4个并行Pylint子进程,其中每个提供的模块将被并行检查。检查程序发现的问题不会立即显示出来。它们在检查模块完成后显示。

在当前实现中并行运行检查有一些限制。不可以使用自定义插件(即--load-plugins选项),也不可能使用初始化钩子(即--init-hook选项)。

退出码

Pylint返回位编码的退出代码。如果适用,下表列出了相关的stderr流消息输出。

exit codemeaningstderr stream message
0no error
1fatal message issued
2error message issued
4warning message issued
8refactor message issued
16convention message issued
32usage error“internal error while receiving resultsfrom child linter”
“Error occurred, stopping the linter.”
“<return of linter.help()>”
“Jobs number <#> should be greater than 0”
“<IOError message when trying to open output file>”

Pylint的输出

输出的默认格式是原始文本。可以通过向pylint传递--output-format=<value>选项来改变这一点。可能的值有:json, parseable, colorized和msvs (visual studio)。

通过传递--output-format一个以逗号分隔的格式列表,可以同时使用多种输出格式。若要更改单个格式的输出文件,请在分号后指定。例如,你可以同时保存一个json报告到somefile和打印一个彩色报告到stdout:

--output-format=json:somefile,colorized

此外,您可以使用--msg-template=<format string>选项自定义信息显示的确切方式。格式字符串使用Python的新格式语法,并且可用以下几个字段:

path
	relative path to the file

abspath
	absolute path to the file

line
	line number

column
	column number

module
	module name

obj
	object within the module (if any)

msg
	text of the message

msg_id
	the message code (eg. I0011)

symbol
	symbolic name of the message (eg. locally-disabled)

C
	one letter indication of the message category

category
	fullname of the message category

例如,之前版本(1.0之前)的默认格式可以通过以下方式获得:

pylint --msg-template='{msg_id}:{line:3d},{column}: {obj}: {msg}'

其他一些例子:

  • the default format:

    {path}:{line}:{column}: {msg_id}: {msg} ({symbol})
    
  • Visual Studio兼容格式(以前的msvs输出格式):

    {path}({line}): [{msg_id}{obj}] {msg}
    
  • 可解析(Emacs和所有,以前的’parseable输出格式)格式:

    {path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
    

--msg-template选项只能与基于文本的报告(--output-format可以是未指定的,也可以是:parseablecolorizedmsvs之一)组合。如果同时指定了--output-format--msg-template,那么--msg-template选项将优先于报告器类定义的默认行格式。

源码分析部分

对于每个python模块,Pylint将首先显示几个’*'字符,后面跟着模块的名称。然后,一些信息的格式如下:

MESSAGE_TYPE: LINE_NUM:[OBJECT:] MESSAGE

您可以获得另一种输出格式,这很有用,因为大多数编辑器或其他开发工具使用——output-format=parseable选项可以识别这种格式。

消息类型可以是以下几种:

  • [I]nformational messages that Pylint emits (do not contribute to your analysis score)

  • [R]efactor for a “good practice” metric violation

  • [C]onvention for coding standard violation

  • [W]arning for stylistic problems, or minor programming issues

  • [E]rror for important programming issues (i.e. most probably bug)

  • [F]atal for errors which prevented further processing
    有时,导致错误的代码行会显示一个指向错误的插入符号。这可能会在Pylint的未来版本中得到推广。
    例如:

************* Module pylint.checkers.format
W: 50: Too long line (86/80)
W:108: Operator not followed by a space
     print >>sys.stderr, 'Unable to match %r', line
            ^
W:141: Too long line (81/80)
W: 74:searchall: Unreachable code
W:171:FormatChecker.process_tokens: Redefining built-in (type)
W:150:FormatChecker.process_tokens: Too many local variables (20/15)
W:150:FormatChecker.process_tokens: Too many branches (13/12)

Reports部分

在分析消息之后,Pylint可以显示一组报告,每个报告关注项目的特定方面,例如按类别划分的消息数量、模块依赖项。这些特性可以通过--reports=y选项或其简写版本-rn启用。
例如,指标报告显示从当前运行中收集的摘要。

  • the number of processed modules

  • for each module, the percentage of errors and warnings

  • the total number of errors and warnings

  • percentage of classes, functions and modules with docstrings, and a comparison from the previous run

  • percentage of classes, functions and modules with correct name (according to the coding standard), and a comparison from the previous run

  • a list of external dependencies found in the code, and where they appear

Score部分

最后,Pylint显示代码的全局评估得分,最高得分为10.0。这个输出可以通过–score=n选项或其简写版本-sn来取消。
也可以使用--evaluation=<python_expression>选项覆盖求值公式。

 类似资料: