【问题标题】:Run Pylint for all Python files in a directory and all subdirectories为一个目录和所有子目录中的所有 Python 文件运行 Pylint
【发布时间】:2016-08-20 18:19:57
【问题描述】:

我有

find . -iname "*.py" -exec pylint -E {} ;\

FILES=$(find . -iname "*.py")
pylint -E $FILES

如果我理解正确,第一个命令将为每个 Python 文件运行 pylint,第二个命令将为所有文件运行一次 pylint。我希望这两个命令会返回相同的输出,但它们会返回不同的结果。我认为这个差异在某种程度上与导入和 F(失败)pylint 消息有关,当导入失败并且 not 由 pylint -E 输出时会发生这种情况。

是否有人已经经历过这种情况并可以解释为什么会发生差异以及运行 pylint 的最佳方式是什么?

【问题讨论】:

    标签: python pylint


    【解决方案1】:

    只需将目录名称传递给 pylint 命令即可。对 ./server 中的所有文件进行 lint:

    pylint ./server
    

    请注意,这需要__init__.py 文件存在于目标目录中。

    【讨论】:

    • 一点也不明显。应该能够做到pylint . 但这不起作用。但这是 the pylint 答案,无需借助外部二进制文件。
    • 要清楚,如果目录不包含__init__.py,那么您不能从您希望运行它的目录server 中运行pylint。 pylint .pylint ../server 都失败了。相反,您必须cd ..; pylint server。另一种方法是创建一个临时的__init__.py,就像 Ryan Feeley 的回答一样。
    • @rahulrachh 你能多说一下你所说的分数是什么意思吗?你的意思是通过/失败分数,还是更像代码覆盖分数?
    • 嗯,在这种情况下,您需要对每个文件单独调用 pylint。只需创建一个循环并在循环中调用 pylint。
    • 这是一个很好的答案,谢谢。或者:pylint ${PWD},如果你想在这里和下面对模块进行 pylint (因为pylint . 不是一个东西)。
    【解决方案2】:

    要在 Git 版本控制中的所有代码上运行 Pylint,

    pylint $(git ls-files '*.py')
    

    非常快,因为 Git 已经知道所有文件的名称。它也适用于缺少 Bash 4 的 macOS 和 Windows。但是,它不会对非常新且尚未 git added 到 repos 的文件进行 lint。

    感谢国宝 Julia Evans 的 git ls-files 技巧 - 这是她的原始用例,使用“entr”自动化工作流程:https://jvns.ca/blog/2020/06/28/entr/

    【讨论】:

    • 我喜欢这个答案,因为它似乎在 PowerShell、MacOS、Linux 等下的 Windows 上也能正常工作......
    • 在拉取请求构建期间运行 pylint 需要这个。这是这个用例的最佳解决方案。
    • 不需要git add
    • 在我的观察中,常规 find 命令比 git ls-files 命令快。
    • 要添加未跟踪的文件,但忽略标准 Git 排除 (.gitignore) 中的文件,我们可以使用以下命令 pylint $( git ls-files --exclude-standard --other -o '*.py'; git ls-files --exclude -o '*.py'; )
    【解决方案3】:

    我的一分钱

    find . -type f -name "*.py" | xargs pylint 
    

    它是如何工作的?

    find 查找所有以py 结尾的文件并传递给xargsxargs 对每个文件运行pylint 命令。

    注意:您也可以为pylint 命令提供任何参数。

    编辑:

    根据doc我们可以使用

    1. pylint mymodule.py

    2. pylint directory/mymodule.py

    3. pylint ./module

    数字 2 如果目录是 python 包(即有一个 __init__.py 文件或者它是一个隐式命名空间包)或者如果“目录”在 python 路径中,则将起作用。

    【讨论】:

    • 这太可怕了。没有以 pylint 为中心的解决方案吗?
    • 如果您没有find,则不可移植。查看其他答案。
    • 这不是我的默认解决方案,但如果您必须使用此解决方案,那么您应该确保明确告诉它忽略您的虚拟环境:find . -type f -not -path "./venv/*" -name "*.py" | xargs pylint
    • 任何想法如何在 Windows 上运行相同的?
    • @jimjim 的微小调整:如果您的虚拟环境被一个点隐藏:find . -type f -not -path "./.venv/*" -name "*.py" | xargs pylint
    【解决方案4】:

    我在根目录下使用:

    pylint *
    

    【讨论】:

    • --ignore 如果你想忽略让我们说你的 virtualenv
    【解决方案5】:

    要在所有子目录中运行 Pylint,

    pylint $(find [a-z]* -type d)
    

    此解决方案比其他解决方案更简单、更直接。它无需设置即可工作,包括在没有 Bash 4 的 macOS 上。

    [a-z]* 的原因是因为大多数项目都有 Git 或其他神奇的子目录,这会污染结果。如果您有以大写字母开头的子目录,请使用此变体:

    pylint $(find [a-zA-Z]* -type d)
    

    【讨论】:

      【解决方案6】:

      pytestpytest-pylint 可以在所有 Python 文件上轻松运行 pylint:

      在项目根目录下的 setup.cfg 文件中,确保至少有:

      [tool:pytest]
      addopts = --pylint 
      

      接下来,在命令行上运行pytest

      【讨论】:

      • 对于已经使用 pytest 的项目来说,这是一个非常好的选择。似乎运作良好。
      【解决方案7】:

      [根据 cmets 中的有用补充更新]

      如果你的目录下没有__init__.py的文件,又因为各种原因不想,我的做法是

      touch __init__.py; pylint $(pwd); rm __init__.py
      

      如果您在该目录中已经有一个__init__.py 文件,它将被删除

      如果您发现自己经常需要此功能,您应该创建一个以更安全的方式执行此操作的函数,以保留预先存在的__init__.py 文件。例如,您可以将以下 pylint_all_the_things 函数放入您的 ~/.bashrc 文件中。 (最后一行导出函数,因此可以从任何子 shell 调用它。)如果您不想编辑 .bashrc,可以将函数体放在可执行的 shell 脚本文件中。

      此函数默认在当前目录中运行 pylint,但您可以指定要用作第一个函数参数的目录。

      # Run pylint in a given directory, defaulting to the working directory
      pylint_all_the_things() {
          local d=${1:-$(pwd)}
      
          # Abort if called with a non-directory argument.
          if [ ! -d "${d}" ]; then
              echo "Not a directory: ${d}"
              echo "If ${d} is a module or package name, call pylint directly"
              exit 1
          fi
      
          local module_marker="${d}/__init__.py"
      
          # Cleanup function to later remove __init__.py if it doesn't currently exist
          [[ ! -f ${module_marker} ]] && local not_a_module=1
          cleanup() {
              (( ${not_a_module:-0} == 1 )) && rm "${module_marker}"
          }
          trap cleanup EXIT
      
          # Create __init__.py if it doesn't exist
          touch "${module_marker}"
          pylint "${d}"
          cleanup
      }
      export -f pylint_all_the_things
      

      trap 实用程序用于确保即使对 pylint 的调用失败并且您启用了 set -e 也会进行清理,这会导致函数在到达清理行之前退出。

      如果你想在当前工作目录和所有子文件夹上递归调用pylint,你可以这样做

      for dir in ./**/ ; do pylint_all_the_things "$dir"; done
      

      这需要在 bash (shopt -s globstar) 中启用 globstar。

      【讨论】:

      • touch __init__.py; pylint `pwd`; rm __init__.py
      • 最好trap 'rm -f __init__.py' EXIT 确保即使 pylint 中止也将其删除。
      • 一个重要的说明 - __init__.py 需要添加到所有带有 .py 文件的子文件夹中。
      • 如果你一开始就有__init__.py,请记住不要删除它。
      • 我做了touch __init__.py; pylint . 但我没有得到任何输出。知道为什么吗?
      【解决方案8】:

      【讨论】:

        【解决方案9】:

        要对目录及其子目录中的所有 *.py 文件运行 pylint,您可以运行:

        shopt -s globstar  # for Bash
        pylint ./**/*.py
        

        【讨论】:

        • 这似乎不起作用。你是从哪个版本的 pylint 和哪个 OS/Shell 运行它的?
        • 或者在一行中同时使用:pylint *.py **/*.py - 对当前目录和所有子目录中的所有 py 文件运行
        • 安装 pylint 开箱后无法运行
        【解决方案10】:

        我使用“pylint_runner”来对目录和子目录中的所有文件运行 pylint。 Python 3.7.4

        pylint_runner 0.54

        pylint 2.4.1

        https://pypi.org/project/pylint_runner/

        这是从 Docker 容器运行它的命令:

        docker run -i --rm --name my_container \
          -v "$PWD":"$PWD" -w "$PWD" \
            python:3.7 \
              /bin/sh -c "pip3 install -r requirements.txt; pylint_runner -v"
        

        requirements.txt - 应该存在于“$PWD”目录中并包含“pylint_runner”条目。

        【讨论】:

          【解决方案11】:

          已经有一个issue for this,希望很快得到修复。

          如果你不喜欢使用xargs,你可以做一个简单的 find-exec:

          find . -type f -name "*.py" -exec pylint -j 0 --exit-zero {} \;
          


          pylint Project-Dir 的问题是所有绝对导入都不起作用。

          【讨论】:

            【解决方案12】:
            1. touch __init__.py在当前目录中
            2. touch __init__.py 在您希望 pylint 查看的每个子目录中
            3. pylint $(pwd)(或等效pylint /absolute/path/to/current/directory

            【讨论】:

              【解决方案13】:

              如果您想运行自定义配置文件,请使用以下命令

              pylint --rcfile=.pylintrc <directory_name>
              

              【讨论】:

                【解决方案14】:

                如果您的目标是在当前工作目录和子文件夹中的所有文件上运行 pylint,这是一种解决方法。此脚本在当前目录上运行 pylint。如果__init__.py 不存在,它会创建它,运行 pylint,然后将其删除。

                #! /bin/bash -
                if [[ ! -e __init__.py ]]; then
                    touch __init__.py
                    pylint `pwd`
                    rm __init__.py
                else
                    pylint `pwd`
                fi
                

                【讨论】:

                • 最好trap 'rm -f __init__.py' EXIT 确保即使 pylint 中止也将其删除。这也将允许摆脱 else 分支。
                • 一个重要的说明 - __init__.py 需要添加到具有 .py 文件的所有子文件夹中。我最终做了类似files=; for d in $(find -name \*.py | xargs dirname | sort -u); do if ! test -f $d/__init__.py; then touch $d/__init__.py; files="$files $PWD/$d/__init__.py"; fi; done; trap "rm -f $files" EXIT
                • 好点——您应该将您的方法作为单独的答案提交,并附上完整的解释。
                猜你喜欢
                • 1970-01-01
                • 2012-09-02
                • 2014-11-10
                • 1970-01-01
                • 1970-01-01
                • 2023-01-04
                • 2016-11-07
                • 2013-06-21
                相关资源
                最近更新 更多