Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why is there no circular import error here? #20

Closed
dariuscosden opened this issue Feb 15, 2021 · 4 comments
Closed

Why is there no circular import error here? #20

dariuscosden opened this issue Feb 15, 2021 · 4 comments
Labels

Comments

@dariuscosden
Copy link

I'm using this repo as the base for my celery implementation in a project. In my project, I am getting circular import errors, but here there aren't. Shouldn't there be?

You have __init__.py, which imports auth from the views folder. auth in turn has some authentication functions, one of which (register) imports the send_email celery task from emails.py. Finally, emails.py imports celery from __init__.py, therefore making it a circular import.

Am I missing something here? I have a very similar setup and I am getting circular import errors.

@miguelgrinberg
Copy link
Owner

I'm not sure if we are looking at the same thing, but __init__.py does not import auth in the global scope, it does so inside the create_app() function. That is not the same. Imports in the global scope run very early, by putting the import of auth inside create_app() it is delayed until everything else has been imported.

@dariuscosden
Copy link
Author

dariuscosden commented Feb 15, 2021

I thought so too, however in my case I still get a circular import error. Here is a very simplified structure for reference:

./init.py

def create_app():
    app = Flask(__name__)

    # Api
    with app.app_context():
        import server.api.post as post_api
        app.register_blueprint(post_api.bp)

    # Rest of stuff

# Celery
def init_celery(app=None):
    app = app or create_app()

    celery = Celery(broker=app.config["CELERY_BROKER_URL"])
    celery.conf.update(app.config)

    class ContextTask(celery.Task):
        """Make celery tasks work with Flask app context"""

        def __call__(self, *args, **kwargs):
            with app.app_context():
                return self.run(*args, **kwargs)

    celery.Task = ContextTask
    return celery

celery_client = init_celery()

./api/post/init.py

from flask import Blueprint
from server.celery_app import do_background_stuff

bp = Blueprint("post", __name__)

@bp.route("/api/v1/posts", methods=["POST"])
def posts():
    do_background_stuff.delay(10)

./celery_app.py

from server import celery_client

@celery_client.task()
def do_background_stuff():
    print('test')

The issue is ./__init__.py importing api.post, which imports do_background_stuff, and that one imports celery_client from ./__init__.py. It's the same structure as this repo isn't it? And the import is inside of the create_app() function as well. Why do you think I'm getting a circular import error?

Edit
Here is the error for reference

ImportError: cannot import name 'celery_client' from partially initialized module 'server' (most likely due to a circular import) (/server/server/__init__.py)

@miguelgrinberg
Copy link
Owner

I can't really help with the information that I have. Seems like a pretty standard circular import problem though. If your import is inside create_app() then you must be calling this function too early, before all other imports have executed.

@dariuscosden
Copy link
Author

Seems to be the case. I temporarily resolved it by importing the celery task on the line right before where I call it but this isn't what I'd call a solution. I'm going to look into it more. I'll close this issue as it doesn't relate to this repo at this point. Thanks a lot for your answers though!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants