Search code examples
pythonpython-3.xflaskflask-restfulflask-pymongo

Can not import mongo object in other file


Using flask-restful, i can not import the object mongo = PyMongo() from the file app/__init__.py into app/common/db.py.

My folder structure looks like this:

myproject/
   run.py
   app/
      __init__.py
      config.py
      common/
         __init__.py
         db.py
      auth/
         __init__.py
         resources.py

app/__init__.py contains:

from flask import Flask, Blueprint
from flask_pymongo import PyMongo
from flask_restful import Api
from app.config import Config

from app.auth.resources import Foo

mongo = PyMongo()

bp_auth = Blueprint('auth', __name__)
api_auth = Api(bp_auth)

api_auth.add_resource(Foo, '/foo/<string:name>')

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    mongo.init_app(app)

    app.register_blueprint(bp_auth)

    return app

app/common/db.py contains:

from app import mongo

the application itself is run from the root via run.py which contains:

from app import create_app

app = create_app()

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

Problem:

Running the application i get an ImportError:

from app import mongo

ImportError: cannot import name 'mongo'

Why this is not working?

Thanks for your help!

EDIT:

Full Traceback:

    Traceback (most recent call last):
  File "run.py", line 1, in <module>
    from app import create_app
  File "/home/bt/Dropbox/dev/flask/test_api/app/__init__.py", line 13, in <module>
    from app.auth.resources import SignIn, Users, User, Foo
  File "/home/bt/Dropbox/dev/flask/test_api/app/auth/resources.py", line 8, in <module>
    from app.common.resources import AuthResource
  File "/home/bt/Dropbox/dev/flask/test_api/app/common/resources.py", line 3, in <module>
    from app.auth.decorators import token_required
  File "/home/bt/Dropbox/dev/flask/test_api/app/auth/decorators.py", line 6, in <module>
    from app.common.database import users
  File "/home/bt/Dropbox/dev/flask/test_api/app/common/database.py", line 1, in <module>
    from app import mongo
ImportError: cannot import name 'mongo'

Solution

  • As I suspected, this is a circular import problem.

    You can track the closed loop of dependencies looking at the traceback:

    app -> resources -> database -> app
    

    This is a common mistake and not properly documented in Flask tutorials. As explained here by Lepture, you should avoid declaring db in the __init__.py

    I always keep this one certain rule when writing modules and packages:

    Don't backward import from root __init__.py.

    How should you do it, then?

    • declare db in the proper module (db.py)
    • import it inside the application factory

    I found myself reluctant towards this pattern, I thought those import statements didn't belong inside a function. But this is the way to go.

    So, your files should look something alike:

    app/common/db.py

    from flask_pymongo import PyMongo
    mongo = PyMongo
    

    app/__init__.py

    from flask import Flask
    ...
    
    def create_app(config_class=Config):
        app = Flask(__name__)
        app.config.from_object(config_class)
    
        from app.common.db import mongo
        mongo.init_app(app)
        ...
    

    and when you need your database connection, i.e. in resources module, you should import it like

    from app.common.db import mongo
    

    Note: to avoid future problems, your blueprints should also be declared elsewhere and import on creation time. I really encourage you to read the post by Lepture to better understand this approach.