Как этот вид импорта считается циклическим (или почему я получаю сообщение об ошибке «ImportError: невозможно импортировать имя EmailMessage») - PullRequest
0 голосов
/ 26 июня 2018

UPDATE :
Ошибка (в данном конкретном случае) была вызвана не циклическим импортом, а недостатком конфигурации virtualenv. См. мой ответ ниже для уточнения.


Я использую:

Я создаю веб-приложение с использованием Flask, помимо прочего мне нужна возможность отправлять почту пользователям. Я построил отдельный модуль Python, который будет отвечать за обработку почты. Хотя я столкнулся со странной (как мне кажется, по крайней мере) проблемой import после того, как я добавил модуль обработки электронной почты в свое приложение.


Вот проблема (изолированная) import, с которой я столкнулся:

app.py

from flask import Flask
from test_mail import EmailTool

app = Flask(__name__)

@app.route('/')
def index():
    return 'Testing!'

test_mail.py

from email.message import EmailMessage

class EmailTool(object):
    pass

После запуска моего приложения и перехода к индексу (т. Е. /) я получаю:

Traceback (most recent call last):
  File "/app.py", line 2, in <module>
    from tmp_test_mail import EmailTool
  File "/test_mail.py", line 1, in <module>
    from email.message import EmailMessage
ImportError: cannot import name EmailMessage

Я изменил код для test_mail.py , чтобы убедиться, что модуль email доступен:

import email

class EmailTool(object):
    pass

Таким образом, я не получаю сообщение об ошибке.

Поиск возможных причин и решений заставил меня поверить ( 1 , 2 , 3 , 4 , 5 ), скорее всего, это связано с циклической ссылкой. Хотя даже после прочтения всех упомянутых материалов и выявления причины проблемы, я все еще не могу понять, как это циркуляр ссылка. Поэтому я делаю вывод, что либо оно не является круговым, а причина кроется в чем-то другом, либо оно круговое, и я упускаю что-то очевидное здесь.


Прошу помощи в понимании следующего:

  1. Считается ли представленный выше случай круговой ссылкой? (Если да, то каким образом это действительно круговой )?
  2. Почему я получаю ошибку, когда я from email.message import EmailMessage, но не получаю сообщение об ошибке, если я вместо этого import email?

Ответы [ 2 ]

0 голосов
/ 27 июня 2018

TL; DR : реальная проблема не имела ничего общего с циклической зависимостью - это оказалось неверной конфигурацией моей виртуальной среды ( Версия Python была на самом деле 2.7.10 , так как было предложено в комментарии hjpotter92 ).


Как я узнал, что это было причиной (публикация в виде набора рецептов для отладки вашего Python venv, который позже мог бы пригодиться для меня и, надеюсь, кого-то еще):

  1. Сразу после прочтения комментариев к моему запросу (в частности, hjpotter92 ) Я поспешил проверить версию Python внутри virtualenv Я запускаю свое приложение из (хотя я проверил его прямо перед публикацией вопроса - вы не можете быть слишком осторожны в таких вещах =).

    Выполняется (внутри виртуальной среды):

    python --version
    

    дал мне (как я и ожидал):

    Python 3.6.1
    
  2. Я не был убежден, хотя =). Как было предложено в этих ответах: 1 и 2 , я добавил следующее к коду для обоих модулей: app.py и test_mail.py (чтобы проверить, какая версия Python они на самом деле побежал на:

    import sys
    ...
    print(sys.version)
    

    он выводил (на удивление для меня):

    2.7.10
    
  3. Хорошо, здесь явно что-то не так. Я решил обновить свои базовые знания по настройке virtualenv. первая статья , на которую я наткнулся, предложила pip --version в качестве второго шага процесса установки (после python --version). Ничего не потеряв, я запустил его (конечно же, в виртуальной среде), и (к моему изумлению) он дал мне:

    pip 9.0.1 from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages (python 2.7)
    

    Итак, каким-то образом pip использованный внутри виртуальной среды был системного уровня один ...

  4. В этот момент у меня возникли сомнения, что мое приложение вообще работает с virtualenv. Следуя рецепту из этого ответа ( и комментарию к нему), я составил и добавил к app.py и test_mail.py следующий фрагмент:

    import sys
    
    ...
    
    if hasattr(sys, 'real_prefix'):
        print('Python 2 venv')
    elif (hasattr(sys, 'base_prefix') and sys.prefix != sys.base_prefix):
        print('Python 3 venv')
    else:
        print('Not venv!')
    

    неудивительно (на данный момент) он печатал Not venv!.

  5. Отладка того, что именно не так в текущей виртуальной среде, казалась дорогостоящей. Итак, что я в итоге сделал:
    • удаление Flask и связанных пакетов (itsdangerous, Jinja2, MarkupSafe, Werkzeug) с системного уровня (которые были установлены там по некоторым причинам) через pip uninstall <package_name>.
    • воссоздание виртуальной среды с python3 -m venv <env_name>

Теперь, чтобы ответить на мои собственные вопросы:

  1. Код в моем вопросе не содержит циклическую ссылку.
  2. Ошибка после попытки сделать from email.message import EmailMessage произошла из-за того, что Python 2.7.10 действительно использовался, и если мы рассмотрим исходный код message.py для этой версии Python, мы будем видим, что он просто не содержит класс с именем EmailMessage. В то время как исходный код message.py для Python 3.6. * Library , содержит класс с именем EmailMessage.
0 голосов
/ 26 июня 2018

Чтобы ответить на оба ваших вопроса:

Первый

Нет, указанный выше код не должен быть круглым, если только email.message содержит ссылки на модуль app, предполагая, что app является допустимым модулем.

Второй

Импорт из email вместо email.messageне вызывает никаких ошибок, потому что вы не импортируете (казалось бы) проблемный класс EmailMessage, поскольку он находится в email.message, а не email.Моя теория заключается в том, что это вызвано некоторым циклом импорта обратно в модуль app, расположенный в модуле email.message.

Примечание:

На момент написания я не знал, что email или email.message были частью стандартной библиотеки (3.6.x), поскольку я никогда не использовал ничего, связанного с этими модулями (и я не использую python 3.x <очень часто), и поэтому я предположил, что это было вызванопо <strong>циклическая ссылка , как предположил автор.Как выясняется (и указывалось в оригинальном сообщении ), это было вызвано чем-то совершенно другим .

...