emvy03
emvy03

Reputation: 133

Flask Circular Dependency: "Cannot import name from partially initialized module"

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

Upvotes: 0

Views: 4428

Answers (1)

Alexander Volkovsky
Alexander Volkovsky

Reputation: 2918

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
    ...

Upvotes: 2

Related Questions