0

I am building a Flask app and following Miguel Grinberg's excellent tutorial/book. I am trying to have a separate worker process execute some tasks. When I include the create_app function in the tasks file at the top of the script as per the structure below I get the error message:

ImportError: cannot import name 'refreshed_google_client' from partially initialized module 'app.tasks' (most likely due to a circular import) (/home/matthew/Documents/flask/artemis-34/app/tasks.py)

However when I move the create_app function to the bottom of the tasks.py I don't get the error and the functionality works. I could leave it at the bottom but I don't think this completely solves the problem, and it would also still be great to understand why the circular dependencies are occuring out of general curiosity.

My app structure looks like:

-->app
   -->__init__.py
   -->decorators.py
   -->models.py
   -->tasks.py
   -->auth
      -->__init__.py
      -->errors.py
      -->forms.py
      -->views.py
   -->main
      -->__init__.py
      -->errors.py
      -->forms.py
      -->views.py
   -->static
   -->templates
-->migrations
config.py
flasky.py
Procfile
requirements.txt
worker.py

app/flasky.py

from flask import Flask,render_template, session, redirect, url_for, flash
import os
from app import create_app,db
from app.models import User,Role
from datetime import datetime
from flask_migrate import Migrate,upgrade

app = create_app(os.getenv('FLASK_CONFIG') or 'default')

app/_ init _.py

from flask import Flask, render_template
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from config import config
from flask_session import Session
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
import rq
from redis import Redis
from flask_login import LoginManager
from worker import conn
import os

bootstrap = Bootstrap()
moment = Moment()
db = SQLAlchemy()
scheduler = BackgroundScheduler()
migrate = Migrate()
session= Session()
login_manager = LoginManager()
login_manager.login_view = 'auth.login'

def create_app(config_name='default'):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    db.init_app(app)
    bootstrap.init_app(app)
    moment.init_app(app)
    migrate.init_app(app,db)
    session.init_app(app)
    login_manager.init_app(app)
    if not scheduler.running:
        scheduler.start()
        jobstore_url = os.environ.get('DATABASE_URL')
        scheduler.add_jobstore(SQLAlchemyJobStore(url=jobstore_url),'sqlalchemy')

    from .main import main as main_blueprint
    from .auth import auth as auth_blueprint

    app.register_blueprint(main_blueprint)
    app.register_blueprint(auth_blueprint,url_prefix='/auth')

    app.task_queue = rq.Queue(connection=conn) #Redis.from_url(os.environ.get(REDIS_URL))

    if app.config['SSL_REDIRECT']:
        from flask_sslify import SSLify
        sslify = SSLify(app)

    return app

app/tasks.py

from . import create_app,db
from .models import User,Tokens,Files
from .decorators import token_getter
from flask_login import current_user
import requests
import datetime as dt
import urllib
import os

app = create_app(os.getenv('FLASK_CONFIG') or 'default')

<FUNCTIONS HERE>

app/auth/views.py

from flask import render_template,url_for,redirect,request,flash,session,current_app,Response
from .. import db,scheduler
from . import auth
from ..models import User,Role,Tokens,Files
from flask_login import login_user, logout_user, login_required
from ..decorators import admin_required, token_setter, token_getter,permission_required
import requests
import urllib
from .forms import LoginForm, SubmitConnection, ScheduleJobForm
from app.tasks import refreshed_google_client,test_context

app/main/views.py

from flask import render_template, session, redirect, url_for, flash,current_app,request
from datetime import datetime
from . import main
from .. import db,scheduler
from ..models import User,Tokens
from .forms import NameForm,AnalyticsForm
from flask_login import login_required,current_user
from ..decorators import admin_required,permission_required
import requests
import rq
from redis import Redis
from app.tasks import refreshed_google_client,load_analytics

1 Answer 1

2

You have the following circular import: create_app -> from .main import main as main_blueprint -> from app.tasks import refreshed_google_client,load_analytics -> create_app

Try to use flask.current_app inside app/tasks.py or move from app.tasks import refreshed_google_client,load_analytics inside your request handler like this:

@main_blueprint.route('/')
def get():
    from app.tasks import refreshed_google_client
    ...
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, Alexander! I did try to use flask.current_app however I got an application context error. I'll try and move the import into the request handler instead as you suggest.
That has solved the issue and proved a valuable lesson on circular imports. Many thanks, Alexander :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.