我无法终生让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的虚拟环境中工作。
答案 0 :(得分:1)
长话短说:您可能希望将foo.pyi
文件移到顶层trymypy
文件夹中,与foo.py
并排,而不是使用一个单独的'stubs'目录。>
长话短说,目前您的设置存在两个问题。
第一个问题是存根的文件夹结构需要反映基础代码的结构方式。因此,由于您想进行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__
,{{1 }}和trymypy.usefoo
)。
一旦加载trymypy.foo
,mypy就不会再尝试重新加载它,这意味着它永远不会打扰检查您指定的存根。
但是,如果您尝试对单个文件(例如trymypy.foo
,mypy -m trymypy.usefoo
)进行类型检查,则mypy不会尝试将所有内容加载到mypy -p trymypy.usefoo
中,这意味着它可以使用以下命令找到存根典型的import resolution rules。
您可以通过传递trymypy
标志来确认所有这些行为,该标志在详细模式下运行mypy并准确打印出加载的内容。每次运行前,请确保删除-v
目录。
注意:实际上,我实际上不知道这种行为差异是故意的还是mypy中的错误。导入规则非常细微。
不过,修复非常简单:只需将.mypy_cache
文件移动到顶级foo.pyi
文件夹中,如下所示:
trymypy
现在,无论以什么顺序导入什么内容,由于两个文件都位于同一目录中,因此mypy将始终同时找到trymypy/
|- __init__.py
|- usefoo.py
|- foo.py
\- foo.pyi
和foo.py
。每当foo.pyi
和py
文件位于同一目录中时,pyi
文件总是会胜出(并且py文件将被忽略)。
关于此新文件夹结构,您可能有两个后续问题:
是否可以使用pyi
中存在的类型提示来对foo.py
的内容进行类型检查?
答案是否定的,目前没有办法。如果您有foo.pyi
,则foo.pyi
的主体实际上会被mypy完全忽略。不过,有些人对adding support for this feature感兴趣,因此您也许可以订阅链接的Github问题进行更新。
创建一个单独的“存根”文件夹最终在这里没有用。那么 有用吗?
答案是,当您要为第三方库添加存根时,它主要有用。我实际上对“为您自己的代码添加存根”工作流程没有很多经验,但是我的理解是,通常以上述方式“内联”此类存根。