#python #pylint #astroid
Вопрос:
В среде Linux у меня есть следующие три файла в папке с именем utils
:
- Пустой файл
__init__.py
- Файл
mymain.py
с именем и следующим содержимым:from mytool import foo
- Файл
mytool.py
со следующим содержимым:from subprocess import check_output def foo(): print("Hello World")
Теперь я создаю виртуальную среду со следующей настройкой:
astroid==2.4.2
isort==5.7.0
lazy-object-proxy==1.4.3
packaging==20.9
pylint==2.6.0
pyparsing==2.4.7
six==1.15.0
toml==0.10.2
typed-ast==1.4.2
wrapt==1.12.1
Затем я запускаю проверку pylint в этой папке
pylint utils
или
pylint --disable=C,R,W utils # only the error is of interest
он должен вернуть оценку 10.
Когда вы теперь обновите версию astroid
до 2.5.0 и снова запустите проверку, вы получите сообщение об ошибке:
************* Module utils.mymain
utils/mymain.py:2:0: E0401: Unable to import 'mytool' (import-error)
Является ли измененное поведение из-за устаревших методов importlib, как указано ЗДЕСЬ?
Интересный факт
Если вы удалите неиспользуемую инструкцию импорта в файле mytool.py
, вы также получите ту же ошибку импорта даже в astroid
версии 2.4.2
Почему; Как неиспользованный импорт может повлиять на результат pylint
проверки?
Подсказка: У меня есть два вопроса.
Комментарии:
1. Эта проблема невоспроизводима. replit.com/@jumpthrowaway/Astroid
Ответ №1:
Проблема не воспроизводима, поэтому трудно сказать, лежат ли в основе проблемы версия astroid и оператор неиспользованного импорта, но мы можем попробовать исследовать другие пути в нашем стремлении лучше понять, что здесь происходит.
В двух словах
Выполнение pylint --disable=C,R,W utils
ведет себя так, как если бы utils импортировался как модуль, что приводит к сбою абсолютного импорта from mytool import foo
.
В деталях
Я полагаю, вы ожидали, что Pylint вернет идеальный результат с момента выполнения python3 utils/mymain.py
из родительской папки или python3 mymain.py
из папки utils.
Увы, эти методы выполнения работают, потому sys.path[0]
что инициализируется путь к папке utils. Таким образом, оператор абсолютного импорта from mytool import foo
выполняется успешно, так как пакет mytool находится в пределах путей, указанных sys.path
.
Однако при выполнении Pylint его __main__.py
файл обрабатывается как основной модуль, а путь к папке utils больше нигде sys.path
не указан, и абсолютный импорт завершается ошибкой.
Вот три различных подхода, которые приводят pylint --disable=C,R,W utils
к получению идеального результата:
- Отредактируйте инструкцию импорта, чтобы она была относительной, т. е. чтобы
from .mytool import foo
. Обратите внимание, что это изменение гарантирует, что вы выполните свой сценарий как модуль из родительской папки (напримерpython3 -m utils.mymain
). - Добавьте папку utils в
PYTHONPATH
перед выполнением сценария или вsys.path
до достижения инструкции абсолютного импорта.Однако, если вы предпочитаете этот подход с использованием абсолютного импорта, я бы рекомендовал изменить структуру проекта, чтобы отразить хорошо разработанный модуль, и правильно импортировать его (например
from <module>.utils.mytool import foo
). Конечно, для этого требуется локальная установка модуля или изменение пути для поддержки импорта. - Попробуйте запустить с Python 2. Это работает без каких-либо изменений из-за устаревшего поведения неявного относительного импорта в Python 2.
Ответы на ваши вопросы о влиянии модуля astroid и заявления о неиспользованном импорте на результат проверки Pylint:
- Поскольку работа Pylint зависит от модуля astroid, ошибка в модуле astroid может повлиять на результат проверки Pylint неожиданным образом, в том числе описанным вами способом.
- Поскольку Pylint был выполнен для всей папки utils, неиспользуемый оператор импорта в utils/mytool.py может появиться как предупреждение, но оно не должно изменять результат проверки Pylint описанным вами способом (если только это не вызовет какое-либо неожиданное поведение в версии с ошибками astroid).
Таким образом, ошибочная версия астроида, с неиспользуемым оператором импорта или без него, может привести к неожиданным результатам. Однако, поскольку проблема не воспроизводима, трудно исследовать, что именно здесь происходит.
Альтернативным объяснением этого загадочного поведения, предложенным официальной документацией Pylint, является установленный модуль с тем же именем, что и протестированный:
Вы должны указать Pylint имя пакета или модуля Python. Pylint не будет импортировать этот пакет или модуль, хотя использует внутренние компоненты Python для их поиска и, как таковой, подчиняется тем же правилам и конфигурации. Вам следует обратить внимание на свой
PYTHONPATH
, так как это распространенная ошибка-анализировать установленную версию модуля вместо версии разработки.
Комментарии:
1. Спасибо за ваш ответ, но вы НЕ отвечаете, ПОЧЕМУ версия astroid влияет на результат этой настройки и почему оператор импорта влияет на результат. Вы сами сказали: «неиспользованный оператор импорта не должен влиять на результат проверки Pylint, как и модуль astroid». Но это был именно мой вопрос. Вы вообще не ответили на мой вопрос.
2. Пожалуйста, попробуйте воспроизвести проблему в новой виртуальной среде. Я полагаю, что вы увидите, что ни версия astroid , ни оператор неиспользованного импорта не влияют на результат проверки Pylint , которая в обоих случаях завершится неудачей из-за оператора абсолютного импорта. Затем попробуйте перечисленные мной подходы и посмотрите, решена ли проблема.
3. Да, я больше не могу это воспроизвести. Похоже, это был «испорченный» virtualenv. Но как может быть испорчен virtualenv? Как проверить, «В порядке»ли virtualenv?
4. Трудно сказать, что именно произошло, без воспроизводимого примера или доступа к проблемной виртуальной среде. Как я уже упоминал в своем ответе, виновником может быть установленный модуль под названием
mytool
. В частности, возможно, что между первым выполнением Pylint (которое сработало) и следующими (которые завершились неудачно) вы удалили модуль , вызванныйmytool
с помощью функцииfoo
, удалив его из виртуальной среды и вызвав, что абсолютный импорт больше не работает.5. Я изменил либо версию
astroid
, либо инструкцию импорта. Я не «случайно» удалил какой — то модуль между испытаниями! Должно быть, что-то еще было сломано . Но что? Как это выяснить??
Ответ №2:
Попробуйте изменить инструкцию импорта
От:
from mytool import foo
Для:
from .mytool import foo
Точка в имени модуля используется для относительного импорта модуля (Ссылка Здесь).