2

I am a newbie to flask, and I had below import related AttributeError when flask run in flask_lab folder.

Any help would be appreciated.

Working Directory:

flask_lab
├── __init__.py
├── Pipfile
├── Pipfile.lock
├── README.md
├── tmp
│   ├── __init__.py
│   └── test.py
└── app.py

flask_lab/app.py:

import os
import click

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

import flask_lab.tmp.test.demo

app = Flask(__name__)
prefix = 'sqlite:////'
app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(app.root_path, 'data.db')
db = SQLAlchemy(app)

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(20))

flask_lab.tmp.test.demo()

flask_lab/tmp/test.py:

import flask_lab.app

print(flask_lab.app.db)


def demo():
    print('yeah!')

Error:

Traceback (most recent call last):
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/bin/flask", line 10, in <module>
    sys.exit(main())
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 894, in main
    cli.main(args=args, prog_name=name)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 557, in main
    return super(FlaskGroup, self).main(*args, **kwargs)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/core.py", line 717, in main
    rv = self.invoke(ctx)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/core.py", line 1137, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/core.py", line 956, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/click/core.py", line 555, in invoke
    return callback(*args, **kwargs)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 767, in run_command
    app = DispatchingApp(info.load_app, use_eager_loading=eager_loading)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 293, in __init__
    self._load_unlocked()
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 317, in _load_unlocked
    self._app = rv = self.loader()
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 377, in load_app
    raise_if_not_found=False)
  File "/home/huafeng/.local/share/virtualenvs/flask_lab-x_qc9OjH/lib/python3.6/site-packages/flask/cli.py", line 235, in locate_app
    __import__(module_name)
  File "/home/huafeng/Desktop/flask_lab/app.py", line 7, in <module>
    import flask_lab.tmp.test.demo
  File "/home/huafeng/Desktop/flask_lab/tmp/test.py", line 3, in <module>
    print(flask_lab.app.db)
AttributeError: module 'flask_lab' has no attribute 'app'

Got complaints from stackoverflow about too many code and not enough details.... more words, more words....

Chet
  • 53
  • 1
  • 7

1 Answers1

2

While interpreting app.py if the python interpreter encounters a line import flask_lab.tmp.test.demo then it will start interpreting tmp/test.py immediately. But tmp/test.py again imports flask_lab.

At this point, since the interpreter had already encountered flask_lab, it will start searching for app in that namespace. But it had never reached till that line. Since you had already imported tmp.test before app was defined in the module, there is no flask_lab.app yet and hence the error.

And if you had called tmp.test directly, you would have encountered a circular import error as well.

So the way out is to avoid the circular import scenario. Move the db object to a separate module and call it in both these modules. Flask-SQLAlchemy provides a method called init_app which is meant for such use case.

Lets create a module called common which will contain the common variables.

flask_lab/common.py

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

flask_lab/app.py:

import os
import click

from flask import Flask
from .common import db
from .tmp.test import demo

class User(db.Model): 
    id = db.Column(db.Integer, primary_key=True) 
    name = db.Column(db.String(20))

app = Flask(__name__)
prefix = 'sqlite:////'
app.config['SQLALCHEMY_DATABASE_URI'] = prefix + os.path.join(app.root_path, 'data.db')
db.init_app(app)

demo()

flask_lab/tmp/test.py:

from .common import db

print(db)


def demo():
    print('yeah!')

Note that I have also replaced the flask_lab imports with relative imports. They are cleaner. The code inside the package should avoid using the package name in the imports. That way if you change the package name later, you can do so without having to change all the code inside.

Community
  • 1
  • 1
suryasankar
  • 4,821
  • 2
  • 14
  • 13
  • Right to the point! Many thanks! For the way of importing modules, I saw [blckknght](https://stackoverflow.com/questions/22187279/python-circular-importing)'s answer before and I took it as rule of thumb. But in case of not having circular import, relative imports looks better for sure. Thanks again. – Chet Apr 16 '19 at 13:51
  • If the answer worked for you, please consider marking it as the accepted answer. Thank you. – suryasankar Apr 16 '19 at 14:36