Mypy не может найти все модули в приложении Python3 Django - PullRequest
0 голосов
/ 13 февраля 2019

Фон

Я работаю в большом репозитории Python3, тип которого проверен Mypy.В соответствии с PEP420 мы не используем __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.

Проблема

Однако тестовое обнаружение с pytest, nose, django и др. Работает иначе, и hello_test.py обычно не импортирует hello_service_test.py.В настоящее время Mypy не может обнаружить hello_service_test.py с помощью mypy ./tests (если не использовать __init__.py).

Аналогично, все в каталоге scripts будет страдать от той же проблемы.

Вопрос

Как настроить Mypy таким образом, чтобы каталоги scripts и tests всегда проверялись на тип?

Конфигурация

# 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.

1 Ответ

0 голосов
/ 13 февраля 2019

Это не может быть решено только в Mypy, но вот несколько полезных обходных путей:

1.Loop Over Files в 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

адаптировано из этот ответ

... конечно, если вам нужно это, чтобы выйти с кодом ошибки, вы должны сами подключить его:

{
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 с запросом опции --recursive (или аналогичной), которая предписывает Mypy проверять все .py файлы в указанном каталоге и его подкаталогах.

Надеюсь, этот ответ будет обновлен, и будет доступно лучшее решение.

...