pylint如何在运行时使用easy_install?

How does pylint use easy_install at runtime?

抱歉,这个问题很长。对于 TL;DR 版本,请参阅底部以粗体显示的句子。

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

我在 Ubuntu 16.04 上 运行ning 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

行为是这样的:

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

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

(我只是在每种情况下更改了 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的路径让"no errors"版本开始报错

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

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

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

it creates a special .egg-link file in the deployment directory, that links to your project’s source code. And, ..., it will also update the easy-install.pth file to include your project’s source code

pth 文件将影响 sys.path,后者通过 pylint.utils.expand_modules 影响 module import logic of astroid and it is deeply buried in the call stack of 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'])