Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to solve this circular import error with a Flask blueprint?

Tags:

python

flask

I had a problem with a circular import, so I moved my blueprint import below my app definition. However, I'm still having an import error.

Traceback (most recent call last):
  File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 2217, in <module>
    globals = debugger.run(setup['file'], None, None)
  File "/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevd.py", line 1643, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/Users/benjamin/Documents/Projects/website/server/app/app.py", line 15, in <module>
    from views import site
  File "/Users/benjamin/Documents/Projects/website/server/app/views.py", line 2, in <module>
    from models import User
  File "/Users/benjamin/Documents/Projects/website/server/app/models.py", line 3, in <module>
    from database_setup import db
  File "/Users/benjamin/Documents/Projects/website/server/app/database_setup.py", line 1, in <module>
    from app import app
  File "/Users/benjamin/Documents/Projects/website/server/app/app.py", line 15, in <module>
    from views import site
ImportError: cannot import name site

If I move the blueprint import and registration to if __name__ == '__main__':, the problem goes away, but I'm not sure if this is a good idea.

if __name__ == '__main__':
    from views import site
    app.register_blueprint(site)
    app.run()

Is this the right way to solve the problem, or is there another solution?


original app.py without __main__ "fix":

from flask import Flask

app = Flask(__name__)

from views import site
app.register_blueprint(site)

if __name__ == '__main__':
    app.debug = True
    app.run()

views.py:

from flask import Blueprint, render_template

site = Blueprint('site', __name__, template_folder='templates', static_folder='static')

@site.route('/', methods=['GET', 'POST'])
def index():
    return render_template('index.html')

database_setup.py:

from app import app
from flask_mongoengine import MongoEngine

app.config['MONGODB_SETTINGS'] = {'db': 'mst_website'}    
db = MongoEngine(app)

models.py:

from database_setup import db

class User(db.Document):
    # ...

My file structure is:

/server
  |-- requirements.txt
  |-- env/ (virtual environment)
  |-- app/ (my main app folder)
       |-- static/
       |-- templates/
       |-- __init__.py
       |-- app.py
       |-- database_setup.py
       |-- models.py
       |-- views.py
like image 327
benjaminz Avatar asked Jun 10 '15 15:06

benjaminz


People also ask

How do I resolve circular import error?

Changing the name of the Working file different from the module which is imported in the script can avoid the Circular Imports problem. Import the module: Avoid importing objects or functions from a module that can cause Circular Imports. It is good to import the whole module to avoid the Circular Import.

How do I import blueprints into flask?

To use any Flask Blueprint, you have to import it and then register it in the application using register_blueprint() . When a Flask Blueprint is registered, the application is extended with its contents. While the application is running, go to http://localhost:5000 using your web browser.


1 Answers

You have a circular import in your code. Based on the traceback:

  1. app.py does from views import site
  2. views.py does from models import User
  3. models.py does from database_setup import db
  4. database_setup.py does from app import app
  5. app.py does from views import site

Based on these order of events, the app.py you've posted isn't the one that's actually causing your problem. Right now, app hasn't been defined before views is imported, so when further down the chain it tries to get app, it's not available yet.

You need to restructure your project so that everything that depends on app is imported after app is defined. From your question, it seems like you think you did, but perhaps there's still an import written above app that you missed.


Probably unrelated, but you are currently using "relative" imports, which are discouraged. Rather than doing from views import site, etc., you should do an absolute path: from app.views import site, or a relative path: from .views import site.


To answer the initial question of "is using __main__ to import blueprints a good idea?", it is not. The problem with that is that the __main__ guard is only executed when you run the module directly. When you go to deploy this using a real app server such as uWSGI or Gunicorn, none of your blueprints will be imported or registered.

like image 137
davidism Avatar answered Sep 27 '22 19:09

davidism