以编程方式调用 Pylint

发布于 2024-08-16 21:37:51 字数 512 浏览 6 评论 0原文

我想调用 Pylint 检查器,仅限于错误信号部分,作为我的单元测试的一部分。因此,我检查了 Pylint 可执行脚本,进入了 pylint.lint.Run 帮助程序类,在那里我迷失在一个相当长的 __init__ 函数中,以调用 <代码>sys.exit()。

有人尝试过并成功做到过吗?

梦想计划是这样的:

if __name__ == '__main__':
  import pylint.lint
  pylint.lint.something(__file__, justerrors=True)
  # now continue with unit testing

有什么提示吗?除了“复制 __init__ 方法并跳过 sys.exit() ”,我的意思是?

我不需要需要由 Pylint 运行测试,它也可能是 pyflakes 或其他软件:请随意建议替代方案。

I'd like to invoke the Pylint checker, limited to the error signalling part, as part of my unit testing. So I checked the Pylint executable script, got to the pylint.lint.Run helper class and there I got lost in a quite long __init__ function, ending with a call to sys.exit().

Anybody ever tried and managed to do so?

The dream-plan would be this:

if __name__ == '__main__':
  import pylint.lint
  pylint.lint.something(__file__, justerrors=True)
  # now continue with unit testing

Any hints? Other than "copy the __init__ method and skip the sys.exit()", I mean?

I don't need the tests to be run by Pylint, it might as well be pyflakes or other software: feel free to suggest alternatives.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

故人的歌 2024-08-23 21:37:51

查看 pylint/epylint.py 文件,其中包含两种以编程方式启动 Pylint 的不同方法。

您也可以简单地拨打电话。

from pylint.lint import Run
Run(['--errors-only', 'myfile.py'])

例如,

Take a look at the pylint/epylint.py file which contains two different ways to start Pylint programmatically.

You can also simply call

from pylint.lint import Run
Run(['--errors-only', 'myfile.py'])

for instance.

谈下烟灰 2024-08-23 21:37:51

我最近遇到了同样的问题。
syt 是对的,pylint.epylint 里面有几个方法。然而,它们都调用了一个子进程,其中 python 再次启动。就我而言,这变得相当慢。

根据 mcarans 的答案构建,并发现有一个标志出口,我执行了以下操作,

class WritableObject(object):
    "dummy output stream for pylint"
    def __init__(self):
        self.content = []
    def write(self, st):
        "dummy write"
        self.content.append(st)
    def read(self):
        "dummy read"
        return self.content
def run_pylint(filename):
    "run pylint on the given file"
    from pylint import lint
    from pylint.reporters.text import TextReporter
    ARGS = ["-r","n", "--rcfile=rcpylint"]  # put your own here
    pylint_output = WritableObject()
    lint.Run([filename]+ARGS, reporter=TextReporter(pylint_output), exit=False)
    for l in pylint_output.read():
        do what ever you want with l...

在我的情况下速度大约快了 3 倍。
这样我就完成了整个项目,使用完整的输出来检查每个源文件,指出错误,并对所有文件进行排序。

I got the same problem recently.
syt is right, pylint.epylint got several methods in there. However they all call a subprocess in which python is launched again. In my case, this was getting quite slow.

Building from mcarans answer, and finding that there is a flag exit, I did the following

class WritableObject(object):
    "dummy output stream for pylint"
    def __init__(self):
        self.content = []
    def write(self, st):
        "dummy write"
        self.content.append(st)
    def read(self):
        "dummy read"
        return self.content
def run_pylint(filename):
    "run pylint on the given file"
    from pylint import lint
    from pylint.reporters.text import TextReporter
    ARGS = ["-r","n", "--rcfile=rcpylint"]  # put your own here
    pylint_output = WritableObject()
    lint.Run([filename]+ARGS, reporter=TextReporter(pylint_output), exit=False)
    for l in pylint_output.read():
        do what ever you want with l...

which is about 3 times faster in my case.
With this I have been going through a whole project, using full output to check each source file, point errors, and rank all files from their note.

落在眉间の轻吻 2024-08-23 21:37:51

我们可以使用 StringIO,而不是创建 WritableObject 类。 StringIO 包含 write 方法。

import sys
try:
    from io import StringIO
except:
    from StringIO import StringIO

stdout = sys.stdout
sys.stdout = StringIO()

ARGS = ["-r","n", "--rcfile=rcpylint"]
r = lint.Run(['../test.py']+ARGS, exit=False)

test = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = stdout

print (test.split('\n'))

资料来源:

Instead of creating a WritableObject class we can use StringIO. StringIO contains write method.

import sys
try:
    from io import StringIO
except:
    from StringIO import StringIO

stdout = sys.stdout
sys.stdout = StringIO()

ARGS = ["-r","n", "--rcfile=rcpylint"]
r = lint.Run(['../test.py']+ARGS, exit=False)

test = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = stdout

print (test.split('\n'))

Source:

流殇 2024-08-23 21:37:51

我很高兴我遇到了这个。我在这里使用了一些答案和一些主动提出:

# a simple class with a write method
class WritableObject:
    def __init__(self):
        self.content = []
    def write(self, string):
        self.content.append(string)
pylint_output = WritableObject()

pylint = lint.Run(args, reporter=ParseableTextReporter(pylint_output), exit=False)

上面的 Args 是一个字符串列表,例如。 [“-r”,“n”,“myfile.py”]

I'm glad I came across this. I used some of the answers here and some initiative to come up with:

# a simple class with a write method
class WritableObject:
    def __init__(self):
        self.content = []
    def write(self, string):
        self.content.append(string)
pylint_output = WritableObject()

pylint = lint.Run(args, reporter=ParseableTextReporter(pylint_output), exit=False)

Args in the above is a list of strings eg. ["-r", "n", "myfile.py"]

自控 2024-08-23 21:37:51

笔记:
在某些时候,pylint 改变了界面。上面的示例需要将 exit=False 替换为 do_exit=False。 (@mad7777,@amit-tripathi)

(根据 https://github.com 学习/carsongee/pytest-pylint/issues/80

NOTE:
At some point pylint changed the interface. The above examples need to replace exit=False with do_exit=False. (@mad7777, @amit-tripathi)

(Learned as per https://github.com/carsongee/pytest-pylint/issues/80)

飞烟轻若梦 2024-08-23 21:37:51

这是我用来以编程方式调用 pylint 的包装器,因此我有一个 --fail-under arg 来覆盖默认的 pylint 退出代码(对于 CI 很有用)。该代码片段使用 pylint 2.3.1 进行了测试

""" Execute pylint and fail if score not reached. """
import argparse
import sys
from pylint import lint

desc = "PyLint wrapper that add the --fail-under option."\
       " All other arguments are passed to pylint."
parser = argparse.ArgumentParser(description=desc, allow_abbrev=False)
parser.add_argument('--fail-under', dest='threshold', type=float, default=8,
                    help='If the final score is more than THRESHOLD, exit with'
                    ' exitcode 0, and pylint\'s exitcode otherwise.')

args, remaining_args = parser.parse_known_args()

threshold = args.threshold

run = lint.Run(remaining_args, do_exit=False)
score = run.linter.stats['global_note']

if score < threshold:
    sys.exit(run.linter.msg_status)

Here is a wrapper I use to programmatically call pylint so I have a --fail-under arg to overwite the default pylint exit code (usefull for CI). This snippet was tested using pylint 2.3.1

""" Execute pylint and fail if score not reached. """
import argparse
import sys
from pylint import lint

desc = "PyLint wrapper that add the --fail-under option."\
       " All other arguments are passed to pylint."
parser = argparse.ArgumentParser(description=desc, allow_abbrev=False)
parser.add_argument('--fail-under', dest='threshold', type=float, default=8,
                    help='If the final score is more than THRESHOLD, exit with'
                    ' exitcode 0, and pylint\'s exitcode otherwise.')

args, remaining_args = parser.parse_known_args()

threshold = args.threshold

run = lint.Run(remaining_args, do_exit=False)
score = run.linter.stats['global_note']

if score < threshold:
    sys.exit(run.linter.msg_status)
夏末的微笑 2024-08-23 21:37:51

pylint 的另一个入口点是 epylint.py_run 函数,它实现了 stdout 和 stderr 拦截。然而,如下面的代码所示, pylint 似乎没有在 stdout 中写入其报告:

from pylint import epylint

pylint_stdout, pylint_stderr = epylint.py_run(__file__, return_std=True)
print(pylint_stdout.getvalue())  # -> there is just the final rank, no report nor message
print(pylint_stderr.getvalue())

现在,我发现来自 API 的 pylint 和来自 CLI 的 pylint 不使用相同的默认参数。因此,您只需提供 pylint 所需的参数即可。

from pylint import epylint
options = '--enable=all'  # all messages will be shown
options += '--reports=y'  # also print the reports (ascii tables at the end)

pylint_stdout, pylint_stderr = epylint.py_run(__file__ + ' ' + options, return_std=True)
print(pylint_stdout.getvalue())
print(pylint_stderr.getvalue())

此处所述, pylint 将自行执行解析,并将在标准输出中正确输出预期结果。

Another entry point for pylint is the epylint.py_run function, that implement the stdout and stderr interception. However, as shown in the following code, pylint seems to not write its reports in stdout:

from pylint import epylint

pylint_stdout, pylint_stderr = epylint.py_run(__file__, return_std=True)
print(pylint_stdout.getvalue())  # -> there is just the final rank, no report nor message
print(pylint_stderr.getvalue())

Now, i found that pylint from API and pylint from CLI do not use the same default parameters. So, you just have to provides the parameters you need to pylint.

from pylint import epylint
options = '--enable=all'  # all messages will be shown
options += '--reports=y'  # also print the reports (ascii tables at the end)

pylint_stdout, pylint_stderr = epylint.py_run(__file__ + ' ' + options, return_std=True)
print(pylint_stdout.getvalue())
print(pylint_stderr.getvalue())

As described here, pylint will perform the parsing itself, and will correctly output the expected results in stdout.

鸠书 2024-08-23 21:37:51

正如这里的其他答案所提到的,pylint.lint.Run 是可行的方法,但是,没有很好地演示 Python 3 的具体用途。此外,pylint 提供了一个有用的报告器类,可用于捕获 pylint 运行的输出。所有不同的输出类型都有不同的选项。在以下示例中,我将使用 ColorizedTextReporter 类捕获彩色输出。

从 pylint 2.12

from pylint import lint
from pylint.reporters import text

# list of pylint args to only enable warnings, errors, and fatals
args = ["my_file.py", "--enable=W,E,F"]

pylint_output = StringIO() # need a StringIO object where the output will be stored
reporter = text.ColorizedTextReporter(pylint_output)

run = lint.Run(args, reporter=reporter, exit=False) # exit=False means don't exit when the run is over

score = run.lint.stats.global_note # pylint score out of 10

# also available are stats.error, stats.warnings, etc...

开始 在 pylint 2.12 之前

唯一的区别是 Run().lintstats 对象是一个字典。因此,您可以通过 run.lint.stats.get("global_note") 获得分数

As other answers here have mentioned, pylint.lint.Run is the way to go, however, there is not a good demonstration of Python 3 specific uses. Also, pylint gives a useful reporter class that should be used to capture the output of a pylint run. There are options for all different output types. In the following examples, I'll capture the Colorized output using the ColorizedTextReporter class.

As of pylint 2.12

from pylint import lint
from pylint.reporters import text

# list of pylint args to only enable warnings, errors, and fatals
args = ["my_file.py", "--enable=W,E,F"]

pylint_output = StringIO() # need a StringIO object where the output will be stored
reporter = text.ColorizedTextReporter(pylint_output)

run = lint.Run(args, reporter=reporter, exit=False) # exit=False means don't exit when the run is over

score = run.lint.stats.global_note # pylint score out of 10

# also available are stats.error, stats.warnings, etc...

Before pylint 2.12

The only difference is that the stats object of Run().lint is a dictionary. So you'd get the score by run.lint.stats.get("global_note")

深海不蓝 2024-08-23 21:37:51

要在 python 脚本中获取 pylint 报告,请参阅示例

from pylint import lint
from pylint.reporters import CollectingReporter
from dataclasses import asdict

report = CollectingReporter()
result = lint.Run([TOP_DIR], reporter=report, do_exit=False)

print("result ",result.linter.stats.global_note)

line_format = "{path}:{line}:{column}: {msg_id}: {msg} ({symbol})"
for error in report.messages:
    print(line_format.format(**asdict(error)))

To get pylint report in python script see an example

from pylint import lint
from pylint.reporters import CollectingReporter
from dataclasses import asdict

report = CollectingReporter()
result = lint.Run([TOP_DIR], reporter=report, do_exit=False)

print("result ",result.linter.stats.global_note)

line_format = "{path}:{line}:{column}: {msg_id}: {msg} ({symbol})"
for error in report.messages:
    print(line_format.format(**asdict(error)))
超可爱的懒熊 2024-08-23 21:37:51

基于这里的一些解决方案,我提供了以下解决方案(混合 StringIO 以避免在某些内容已经存在时创建“简单类”)和来自 pylint 的 TextReporter


from io import StringIO
from pylint.lint import Run
from pylint.reporters.text import TextReporter

files =  ["my_file.py"]
pylint_options = ["--disable=line-too-long,import-error,fixme"]

pylint_output = StringIO()
Run(
    files + pylint_options,
    reporter=TextReporter(pylint_output),
    exit=False,
)

for line in pylint_output.getvalue().splitlines():
    ... # do something with each line, like filtering / extracting

您还可以使用 ParseableTextReporter 而不是 TextReporter,结果会略有不同(可能更容易解析):

使用 TextReporter

************* Module my_file
my_file.py:65:0: W0613: Unused argument 'args' (unused-argument)
my_file.py:65:0: W0613: Unused argument 'kwargs' (unused-argument)
my_file.py:90:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:93:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:96:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:99:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:102:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:183:0: C0116: Missing function or method docstring (missing-function-docstring)

------------------------------------------------------------------
Your code has been rated at 9.61/10 (previous run: 9.61/10, +0.00)

使用 ParseableTextReporter code>:

************* Module my_file
my_file.py:65: [W0613(unused-argument), CoverageSummaryTable.__init__] Unused argument 'args'
my_file.py:65: [W0613(unused-argument), CoverageSummaryTable.__init__] Unused argument 'kwargs'
my_file.py:90: [C0116(missing-function-docstring), ProtoLogger.debug] Missing function or method docstring
my_file.py:93: [C0116(missing-function-docstring), ProtoLogger.info] Missing function or method docstring
my_file.py:96: [C0116(missing-function-docstring), ProtoLogger.warning] Missing function or method docstring
my_file.py:99: [C0116(missing-function-docstring), ProtoLogger.error] Missing function or method docstring
my_file.py:102: [C0116(missing-function-docstring), ProtoLogger.critical] Missing function or method docstring
my_file.py:183: [C0116(missing-function-docstring), coverage_output] Missing function or method docstring

------------------------------------------------------------------
Your code has been rated at 9.61/10 (previous run: 9.61/10, +0.00)

这取决于你:)

感谢@mad7777、@Amit Tripathi 和@mcarans

Based on few solutions here, I came with the following (mixing StringIO to avoid creating a "simple class" when something already exists) and the TextReporter from pylint:


from io import StringIO
from pylint.lint import Run
from pylint.reporters.text import TextReporter

files =  ["my_file.py"]
pylint_options = ["--disable=line-too-long,import-error,fixme"]

pylint_output = StringIO()
Run(
    files + pylint_options,
    reporter=TextReporter(pylint_output),
    exit=False,
)

for line in pylint_output.getvalue().splitlines():
    ... # do something with each line, like filtering / extracting

You can also use ParseableTextReporter instead of TextReporter and the results will be slightly different (maybe easier to parse):

With TextReporter:

************* Module my_file
my_file.py:65:0: W0613: Unused argument 'args' (unused-argument)
my_file.py:65:0: W0613: Unused argument 'kwargs' (unused-argument)
my_file.py:90:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:93:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:96:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:99:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:102:4: C0116: Missing function or method docstring (missing-function-docstring)
my_file.py:183:0: C0116: Missing function or method docstring (missing-function-docstring)

------------------------------------------------------------------
Your code has been rated at 9.61/10 (previous run: 9.61/10, +0.00)

With ParseableTextReporter:

************* Module my_file
my_file.py:65: [W0613(unused-argument), CoverageSummaryTable.__init__] Unused argument 'args'
my_file.py:65: [W0613(unused-argument), CoverageSummaryTable.__init__] Unused argument 'kwargs'
my_file.py:90: [C0116(missing-function-docstring), ProtoLogger.debug] Missing function or method docstring
my_file.py:93: [C0116(missing-function-docstring), ProtoLogger.info] Missing function or method docstring
my_file.py:96: [C0116(missing-function-docstring), ProtoLogger.warning] Missing function or method docstring
my_file.py:99: [C0116(missing-function-docstring), ProtoLogger.error] Missing function or method docstring
my_file.py:102: [C0116(missing-function-docstring), ProtoLogger.critical] Missing function or method docstring
my_file.py:183: [C0116(missing-function-docstring), coverage_output] Missing function or method docstring

------------------------------------------------------------------
Your code has been rated at 9.61/10 (previous run: 9.61/10, +0.00)

It's up to you :)

Thanks to @mad7777, @Amit Tripathi, and @mcarans

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文