Mypy无法在Python3 Django App中找到所有模块

问题描述 投票:0回答:1

背景

我在使用Mypy进行类型检查的大型Python3仓库中工作。根据PEP420,我们不使用__init__.py文件。

Mypy最近添加了对隐式命名空间包的支持,但实现现在遵循给定入口点的import语句链。在这个repo的情况下,(一个Django应用程序)有许多动态导入的模块(如中间件)或根本不导入(测试和一次性脚本)。

考虑这个例子:

my-py3-repo/
├── hello/
│   ├── services/
│   │   └── hello_service.py
│   └── hello.py
├── scripts/
│   ├── db/
│   │   └── migrate.py
│   └── manage.py
└── tests/
    └── hello/
        ├── services/
        │   └── hello_service_test.py
        └── hello_test.py

假设hello.py导入hello_service.pyhello命名空间下的所有内容都将按照mypy ./hello的预期进行类型检查。

问题

然而,pytestnosedjango等的测试发现工作方式不同,hello_test.py通常不会导入hello_service_test.py。目前Mypy无法用hello_service_test.py发现mypy ./tests(如果不使用__init__.py)。

同样,scripts目录下的所有内容都会遇到同样的问题。

如何配置Mypy,以便始终对scriptstests目录进行类型检查?

组态

# Pipfile
[dev-packages]
mypy = "==0.670"
[requires]
python_version = "3.7"
# setup.cfg
[mypy]
python_version = 3.7
ignore_missing_imports = True
namespace_packages = True

另见我在Mypy仓库中创建的this issue

python django python-3.x mypy
1个回答
0
投票

这在单独的Mypy中无法解决,但这里有一些有用的解决方法:

1.在Bash中循环文件

简单版本:

find . -iname '*.py' ! -name '__init__.py' | xargs mypy

但是如果任何两个文件具有相同的名称,则会失败(因为Mypy尝试将它们作为顶级模块导入)。根据您的目录结构,您可以通过循环共享模块名称的单独应用程序/服务来解决此问题:

for dir in ./myapp/*/;
    do find ${dir%*/} -iname '*.py' ! -name '__init__.py'\
    | xargs pipenv run mypy;
done

改编自this answer

...当然如果您需要使用错误代码退出,您必须自己连线:

{
EXIT_STATUS=0
for dir in ./myapp/*/;
    do find ${dir%*/} -iname '*.py' ! -name '__init__.py'\
    | xargs pipenv run mypy;
    if [ $$? -eq 1 ]; then EXIT_STATUS=1; fi; \
done;
exit $EXIT_STATUS;
}

2.只需使用初始化文件

只需放弃并将__init__.py文件放在Mypy通过import链找不到的任何模块旁边。

我已经向Mypy repo提交了一个feature request,请求一个--recursive选项(或类似的),它将指示Mypy键入检查给定目录及其子目录下的所有.py文件。

希望这个答案将在可用时通过更好的解决方案进行更新。

© www.soinside.com 2019 - 2024. All rights reserved.