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

时间:2019-02-13 19:04:11

标签: python django python-3.x mypy

背景

我在一个大型的Python3存储库中工作,该存储库已通过Mypy进行类型检查。根据{{​​3}},我们不使用__init__.py文件。

Mypy最近增加了对隐式名称空间包的支持,但是该实现现在遵循来自给定入口点的import语句链。对于此回购,(一个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.py,则hello命名空间下的所有内容都会使用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存储库中创建的PEP420

1 个答案:

答案 0 :(得分: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存储库提交了feature request,请求一个--recursive选项(或类似选项),该选项将指示Mypy在以下位置键入检查 all .py文件给定目录及其子目录。

希望此答案将在可用时以更好的解决方案进行更新。