如何正确设置 MYPYPATH 以获取 mypy 的存根?

How do I correctly set MYPYPATH to pick up stubs for mypy?

我这辈子都无法让 MyPy 找到未与其源代码放在一起的存根。这是我的项目结构:

trymypy/
|- stubs/
|  \- foo.pyi
|- __init__.py
|- usefoo.py
\- foo.py
# foo.py
def foofunc(x):
    return str(x)
# usefoo.py
from trymypy.foo import foofunc

print(foofunc(5) + 5)
# stubs/foo.pyi
def foofunc(x: int) -> str: ...

我已将 MYPYPATH 环境变量设置为 /full/path/to/trymypy/stubs,这样 MyPy 应该在 stubs 目录中查找我的 .pyi 文件。

这不应该通过类型检查。 MyPy 应该这样标记错误:

../trymypy/usefoo.py:3: error: Unsupported operand types for + ("str" and "int")

相反,MyPy 不会标记任何错误,因为它没有读取存根文件。如果我将存根文件 foo.pyi 移动到目录的根项目,与 foo.py 位于同一位置,它会正确标记,这向我表明 MYPYPATH 没有被拾取,或者未正确定义。

我也试过在配置文件中设置 mypy_path mypy.ini:

[mypy]
python_version = 3.7
mypy_path = /full/path/to/trymypy/stubs

mypy.ini 中的其他配置选项确实会被拾取(例如 python_version),因此 MyPy 正在查看并读取文件。

完全被难住了。这是一个(非常)简单的示例,看起来它应该像 MyPy 所记录的那样工作。我 运行 没有变量来试验以使其正常工作。

我正在使用 Python 3.7,并且在只安装了 mypy 的虚拟环境中工作。

长话短说:与其拥有单独的 'stubs' 目录,不如将 foo.pyi 文件移动到顶级 trymypy 文件夹中,与 [=14= 一起].


长话短说,目前您的设置有两个问题。

第一个问题是存根的文件夹结构需要反映底层代码的结构方式。所以既然你想做from trymypy.foo import blah,你需要调整你的文件夹结构如下:

trymypy/
|- stubs/
|  |- trymypy/
|  |  |- __init__.pyi
|  \  \- foo.pyi
|- __init__.py
|- usefoo.py
\- foo.py

您应该继续将 mypypath 设置为指向 trymypy/stubs。您可以使用绝对路径或相对路径。

第二个更大的问题是,您的存根可能最终会被隐藏和忽略,具体取决于您调用 mypy 的方式。例如,如果您 运行 mypy -p trymypy 来自 trymypy 文件夹之外,mypy 将首先解析每个 trymypy 和它直接包含的两个子模块(trymypy.__init__ , trymypy.usefoo, 和 trymypy.foo).

并且一旦 trymypy.foo 被加载,mypy 将不会再次尝试重新加载它,这意味着它永远不会检查您指定的存根。

但是如果你尝试对单个文件进行类型检查(例如 mypy -m trymypy.usefoomypy -p trymypy.usefoo),mypy 不会尝试加载 trymypy 中的所有内容,这意味着它可以找到存根使用典型的 import resolution rules.

您可以通过传入 -v 标志自行确认所有这些行为,运行s mypy 处于详细模式并准确打印出加载的内容。一定要删除每个运行.

前的.mypy_cache目录

注意:老实说,我不知道这种行为差异是故意的还是 mypy 中的错误。导入规则非常微妙。


谢天谢地,修复非常简单:只需将 foo.pyi 文件移动到顶级 trymypy 文件夹中,如下所示:

trymypy/
|- __init__.py
|- usefoo.py
|- foo.py
\- foo.pyi

现在,无论以什么顺序导入什么,mypy 总是会同时找到 foo.pyfoo.pyi,因为这两个文件位于同一目录中。每当 pypyi 文件位于同一目录中时,pyi 文件总是胜出(并且忽略 py 文件)。


关于这个新的文件夹结构,您可能有两个后续问题:

  1. 有没有办法使用 foo.pyi 中的类型提示对 foo.py 的内容进行类型检查?

    答案是否定的,目前没有办法。如果你有 foo.pyi 存在, foo.py 的主体基本上被 mypy 完全忽略。不过有人对 adding support for this feature 感兴趣,所以您或许可以订阅链接的 Github 问题以获取更新。

  2. 创建一个单独的 "stubs" 文件夹最终在这里没有用。那么什么时候有用呢?

    答案是,当您想为第三方库添加存根时,它主要有用。我实际上对 "add stubs for your own code" 工作流程没有太多经验,但我的理解是,此类存根通常 "inlined" 以上述方式。