Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"ImportError: cannot import name mail" in Flask

Tags:

python

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
like image 811
Xar Avatar asked Oct 19 '13 12:10

Xar


1 Answers

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.

like image 144
Mark Hildreth Avatar answered Sep 24 '22 01:09

Mark Hildreth