【问题标题】:How does pylint use easy_install at runtime?pylint 如何在运行时使用 easy_install?
【发布时间】:2017-09-08 15:22:53
【问题描述】:

抱歉,这是一个很长的问题。请参阅 TL;DR 版本底部的粗体句子。

我花了很多时间试图找出 pylint 有时不会报告模块中的所有错误的问题。请注意,它确实发现了一些错误(例如长行),但不是全部(例如缺少文档字符串)。

我在 Ubuntu 16.04 上运行 pylint 1.7.2。 (apt 提供的版本是 1.5.2,但通过 pip 安装会得到 1.7.2。)

我们通常从 tox 运行 pylint,tox.ini 看起来像这样(这是一个缩减版):

[tox]
envlist = py35
[testenv]
setenv =
    MODULE_NAME=our_module
ignore_errors = True
deps =
    -r../requirements.txt
whitelist_externals = bash
commands =
    pip install --editable=file:///{toxinidir}/../our_other_module
    pip install -e .
    bash -c \'set -o pipefail; pylint --rcfile=../linting/pylint.cfg our_module | tee pylint.log\'

除其他外,../requirements.txt 文件包含pylint==1.7.2 的一行。

行为是这样的:

  • [错误] 当存在导入 our_other_module 的行时,pylint 似乎已成功完成并且不报告任何警告,即使它应该获取的 our_module 代码中有错误。

  • [正确] 当该行被注释掉时,pylint 会生成预期的警告。

作为追踪此问题的一部分,我复制了 .tox 文件夹的两个副本,其中包含和不包含模块导入,分别命名为 .tox-no-errors-reported.tox-with-errors-reported

所以现在,即使没有采购他们各自的 tox virtualenvs,我也可以执行以下操作:

  • $ .tox-no-errors-reported/py35/bin/pylint --rcfile=../linting/pylint.cfg our_module -- 报告没有 linting 警告

  • $ .tox-with-errors-reported/py35/bin/pylint --rcfile=../linting/pylint.cfg our_module -- 报告预期的 linting 警告

(我只是在每种情况下更改了pylint 脚本的#! 行,以引用该特定.tox 目录中的python3.5,而不是未重命名的.tox

通过区分.tox-no-errors-reported.tox-with-errors-reported,我发现它们非常相似。但是我可以通过从.tox-no-errors-reported/py35/lib/python3.5/site-packages/easy-install.pth 中删除our_other_module 的路径来使“无错误”版本开始报告错误。

所以我的问题是为什么 pylint 在运行时使用 easy_install,它是从我们的其他组件中获取的导致它无法报告某些错误的原因

据我了解,pylint 依赖于 astroidlogilab-common,但在 requirements.txt 中包含这些并没有任何区别。

【问题讨论】:

    标签: python easy-install pylint tox


    【解决方案1】:

    pylint 行为令人惊讶的一个可能原因是 --editable 选项。

    它会在部署目录中创建一个特殊的 .egg-link 文件,该文件链接到您项目的源代码。而且,...,它还会更新 easy-install.pth 文件以包含您项目的源代码

    然后pth 文件将影响sys.path,这会影响astroidmodule import logic,它通过pylint.utils.expand_modules 深埋在pylint.expand_files 的调用堆栈中。此外,pylint 使用 astroid.modutils.get_module_part 标识 AST 中的模块部分和函数名称。

    为了验证理论,您可以尝试手动调用一些受影响的 astroid 函数:

    import sys, astroid
    print(sys.path)
    print(astroid.modutils.get_module_part('your_package.sub_package.module'))
    astroid.modutils.file_from_modpath(['your_package', 'sub_package', 'module'])
    

    【讨论】:

      猜你喜欢
      • 2020-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-13
      • 2013-04-16
      • 2011-04-19
      相关资源
      最近更新 更多