用bazel配置pylint的最佳方法

时间:2017-11-15 09:36:51

标签: bazel pylint

我使用vim作为我的编辑器和Syntastic插件。我试图理解使用像Bazel这样的工具使用pylint的惯用方法。

pylint有一个init-hook命令行参数,可用于动态操作sys.hook。我正在考虑编写一个包装器脚本来执行此操作,但我不确定如何确定正确的事情作为" init-hook"命令。

2 个答案:

答案 0 :(得分:3)

我知道最好的方法是在测试中运行pylint

理想情况下,您对每个文件都有一个linting规则,因此当该文件发生更改时,您只会重新提示该文件。这可能是不切实际的。

规模的另一端是有一个规则来lint项目中的所有文件。即使只有一个文件发生更改,该规则也会重新删除所有文件。所以效率低下。

在我看来,一个良好的中间立场是每个Bazel包装的一个linting规则。

假设您在@local_pylint_config//:pylint下的工作空间中将pylint作为二进制文件,我推荐以下模式:

sh_test(
    name = "lint_test",
    srcs = ["lint_test.sh"],       # this doesn't have to do anything
    data = ["lint_files.out"],
)

genrule(
    name = "lint_files",
    srcs = glob(["**/*.py"]),
    outs = ["lint_files.out"],
    tools = ["@local_pylint_config//:pylint"],
    cmd = "$(location @local_pylint_config//:pylint) $(SRCS) >&/dev/null && md5sum $$(echo $(SRCS) | sort) > $@",
)

注意:

  • 如果测试依赖" lint_files"如果linting成功,可以建立成功。因此,当且仅当linting成功时,测试才会成功。
  • 我使用genrule来确保" pylint"规则是为正确的配置而构建的。
  • 我将pylint的输出重定向到/dev/null以减少构建噪音。
  • 我计算所有源的校验和并将其写入输出文件,以便编写一个独特的输出,该输出完全依赖于源的内容而不是其他任何内容(不是说,不是在当前时间)。我对源文件进行排序以确保输出是确定性的。如果不使用md5sum我只是touch输出文件,输出的内容将独立于来源'内容,因此下游测试规则不会重新运行。
  • 但是,使用... && date > $@代替校验和来源也是合适的,因为如果任何源文件发生变化,Bazel会重建genrule(从而重新提取源文件),从而产生不同的输出因为届时当前时间会发生变化。然而,使用校验和是确定性的。

答案 1 :(得分:0)

您可以创建调用 python 文件的 py_test 调用,它会自动扭曲对 Jeans , Trouserspylint 的调用。并且为了在整个工作区中有更多可重用的东西,在 py_test 周围创建一个宏。我在 Experimentations on Bazel: Python (3), linter & pytest 中解释了详细的解决方案,并附有源代码链接。

pytest --pylint 中创建 python 工具(wrapp 调用 pytest,或仅 pylint)

tools/pytest/pytest_wrapper.py

import sys import pytest # if using 'bazel test ...' if __name__ == "__main__": sys.exit(pytest.main(sys.argv[1:])) 中创建宏

tools/pytest/defs.bzl

公开来自"""Wrap pytest""" load("@rules_python//python:defs.bzl", "py_test") load("@my_python_deps//:requirements.bzl", "requirement") def pytest_test(name, srcs, deps = [], args = [], data = [], **kwargs): """ Call pytest """ py_test( name = name, srcs = [ "//tools/pytest:pytest_wrapper.py", ] + srcs, main = "//tools/pytest:pytest_wrapper.py", args = [ "--capture=no", "--black", "--pylint", "--pylint-rcfile=$(location //tools/pytest:.pylintrc)", # "--mypy", ] + args + ["$(location :%s)" % x for x in srcs], python_version = "PY3", srcs_version = "PY3", deps = deps + [ requirement("pytest"), requirement("pytest-black"), requirement("pytest-pylint"), # requirement("pytest-mypy"), ], data = [ "//tools/pytest:.pylintrc", ] + data, **kwargs ) 的一些资源

tools/pytest/BUILD.bazel

从您的包中调用它 exports_files([ "pytest_wrapper.py", ".pylintrc", ])

BUILD.bazel

然后调用 load("//tools/pytest:defs.bzl", "pytest_test") ... pytest_test( name = "test", srcs = glob(["*.py"]), deps = [ ... ], ) pylint, pytest, back,... 是测试流程的一部分