Flask - avoid circular imports with app factory

8-Bit Borges

I have structured my flask app in such a way that an app factory unifies all __init__.py files into one app object, like so:

app.py
tasks.py
     /project/
             __init__.py
             routes/
                   __init__.py
                   auth_bp.py
                   register_bp.py
             models/
                   __init__.py
                   user.py
                   base.py

app.py

from project import create_app

app = create_app()

project/__init__.py

from flask import Flask

def create_app():

    from . import routes, models

    app = Flask(__name__)
    models.init_app(app)
    routes.init_app(app)

    return app

project/models/__init__,py

from base import db

def init_app(app):
    db.init_app(app)

project/routes/__init__.py

from auth import auth_bp
from register import register_bp

def init_app(app):
    app.register_blueprint(auth_bp)
    app.register_blueprint(register_bp) 

what I'm trying to wrap my head around is how to structure some background processes which depend on app.context(), like so:

project/tasks.py

import sys
sys.path.append('/path/to/root') 

from app import app

def load_cache(track_and_features):
    while True:
        with app.app_context():           
            Upload_Track(track_and_features) 

@app.route('/cache')
def cache(track_and_features):
    executor.submit(load_cache, track_and_features)
    return 'Ok'

the problem (I guess) occurs here, when I call cache(), in a module which imports the app object on its turn:

project/routes/auth_bp.py

from tasks import cache

@auth_bp.route("/callback/q")
def callback():
    (...)
    cache()
    return redirect(url_for('register.homepage'))

I am getting the error:

  File "app.py", line 6, in <module>
    app = create_app()
  File "/Users/me/Documents/Code/Apps/Production/project/__init__.py", line 20, in create_app
    from . import routes
  File "/Users/me/Documents/Code/Apps/Production/project/routes/__init__.py", line 1, in <module>
    from auth import auth_bp
  File "/Users/me/Documents/Code/Apps/Production/project/routes/auth.py", line 18, in <module>
    from tasks import cache
  File "/Users/me/Documents/Code/Apps/Production/tasks.py", line 4, in <module>
    from app import app
  File "/Users/me/Documents/Code/Apps/Production/app.py", line 6, in <module>
    app = create_app()
  File "/Users/me/Documents/Code/Apps/Production/project/__init__.py", line 20, in create_app
    from . import models, routes, services
ImportError: cannot import name routes

How do I fix this?

Martijn Pieters

Don't import app in routes. With an app factory, you do not have an app to register routes with, outside of the factory. Instead, use blueprints for all your views, and import the blueprint into the factory. You could still register your views with the app object inside the factory, but that's just not nearly as clean as just using a blueprint to register views with.

You already do this with dedicated init_app() functions, but your project/routes/tasks.py module doesn't follow this pattern. It too should be using a blueprint. You can share a blueprint between modules, if that simplifies your application.

The only point you actually create an app name, is to run the whole app, so for the WSGI server, tests or command-line tools.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related