Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
378 views
in Technique[技术] by (71.8m points)

python - "ImportError: cannot import name mail" in Flask

I have built is a simple web app with Flask and Python, which I intend to upload to Heroku.

When starting my app locally, with the following script:

#!venv/bin/python
from app import app
app.run(debug = True)

I get this error message:

Traceback (most recent call last):
File "./run.py", line 2, in <module>
    from app import app, mail
File "/home/ricardo/personalSite/app/__init__.py", line 3, in <module>
    from app import index
File "/home/ricardo/personalSite/app/index.py", line 6, in <module>
    from emails import send_email
File "/home/ricardo/personalSite/app/emails.py", line 2, in <module>
    from app import app, mail
ImportError: cannot import name mail

So, it cannot import mail.

Inside the app directory I have this __init__.py, here is were I create the Mail object that is ginving me trouble to import:

from flask import Flask
app = Flask(__name__)
from app import index
from flask.ext.mail import Mail
mail = Mail(app)

And this is the file emails.py where I call the send_mail function:

from flask.ext.mail import Message
from app import app, mail
from flask import render_template
from config import ADMINS
from decorators import async

So, according to the error message, the error is in this file, in the from app import app, mail.

What is the problem? Why can't it import mail?

Update:

This is my directory listing:

persSite
  venv
    <virtual environment files>
  app
    static
    templates
    __init__.py
    index.py
    emails.py
    decorators.oy
  tmp
  run.py
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You have a circular dependency. You have to realize what Python is doing when it imports a file.

Whenever Python imports a file, Python looks to see if the file has already started being imported before. Thus, if module A imports module B which imports module A, then Python will do the following:

  • Start running module A.
  • When module A tries to import module B, temporarily stop running module A, and start running module B.
  • When module B then tries to import module A, then Python will NOT continue running module A to completion; instead, module B will only be able to import from module A the attributes that were already defined there before module B started running.

Here is app/__init__.py, which is the first file to be imported.

from flask import Flask
app = Flask(__name__)
from app import index # <-- See note below.
from flask.ext.mail import Mail
mail = Mail(app)

When this file is imported, it is just Python running the script. Any global attribute created becomes part of the attributes of the module. So, by the time you hit the third line, the attributes 'Flask' and 'app' have been defined. However, when you hit the third line, Python begins trying to import index from app. So, it starts running the app/index.py file.

This, of course, looks like the following:

from flask.ext.mail import Message
from app import app, mail # <-- Error here
from flask import render_template
from config import ADMINS
from decorators import async

Remember, when this Python file is being imported, you have thus far only defined Flask and app in the app module. Therefore, trying to import mail will not work.

So, you need to rearrange your code so that if app.index relies on an attribute in app, that app defines that attribute before attempting to import app.index.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

57.0k users

...