I have suffered from some problems with my code for a some hours.
I'm sure that it is caused by a circular import issue, but I have another question.
I have two blueprint, auth and main. I just return a render_template without any data passing, and things all go good. But when I try to shwo something in my main.index, suddenly an error occured.
I wonder why it works fine just in auth.views while there does have a circular import issue?
my tree struct
app
|- auth
|- __init__.py
|- forms.py
|- views.py
|- main
|- __init__.py
|- forms.py
|- views.py
|- template
|- __init__.py
|- models.py
config.py
manage.py
datta.sqlite
In auth.__init__.py:
from flask import Blueprint
auth = Blueprint("auth", __name__)
from . import views
and in auth.views.py
from app.auth import auth
from app.models import *
from manage import app
#auth.route('/')
def index():
page = request.args.get("page", 1, type=int)
articles = Article.query.order_by(Article.update_time.desc()).paginate(
page, app.config["ARTICLES_PER_PAGE"], False)
next_url = url_for('auth.index', page=articles.next_num if articles.has_next else None)
prev_url = url_for('auth.index', page=articles.prev_num if articles.has_prev else None)
return render_template('index.html', articles=articles.items,
next_url=next_url, prev_url=prev_url)
In main.__init__.py:
from flask import Blueprint
main = Blueprint("main", __name__)
from . import views
In main.views.py:
from app.main import main
from app.models import *
from manage import app
#main.route('/')
def index():
page = request.args.get("page", 1, type=int)
articles = Article.query.order_by(Article.update_time.desc()).paginate(
page, app.config["ARTICLES_PER_PAGE"], False)
next_url = url_for('main.index', page=articles.next_num if articles.has_next else None)
prev_url = url_for('main.index', page=articles.prev_num if articles.has_prev else None)
return render_template('index.html', articles=articles.items,
next_url=next_url, prev_url=prev_url)
In app.__init__.py:
def create_app():
app = Flask(__name__)
app.config.from_object(Config)
Config.init_app(app)
...
from app.main import main
app.register_blueprint(main)
from app.auth import auth
app.register_blueprint(auth, url_prefix='/auth')
return app
in manage.py
from flask_migrate import Migrate, MigrateCommand
from flask_script import Manager, Shell
from app import create_app, db
from app.models import *
app = create_app()
manager = Manager(app)
migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)
def make_shell_context():
return dict(db=db, ArticleType=ArticleType, Source=Source,
Article=Article, User=User, Menu=Menu,
ArticleTypeSetting=ArticleTypeSetting)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command("db", MigrateCommand)
if __name__ == '__main__':
app.run(debug=True)
And my traceback are as follow:
Traceback (most recent call last):
File "C:/Users/bohn/Desktop/1pycharm workspace/BlogPoweredByFlask/manage.py", line 7, in <module>
app = create_app()
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\__init__.py", line 30, in create_app
from app.main import main
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\main\__init__.py", line 5, in <module>
from . import views
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\main\views.py", line 5, in <module>
from manage import app
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\manage.py", line 7, in <module>
app = create_app()
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\__init__.py", line 33, in create_app
from app.auth import auth
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\auth\__init__.py", line 5, in <module>
from . import views
File "C:\Users\bohn\Desktop\1pycharm workspace\BlogPoweredByFlask\app\auth\views.py", line 9, in <module>
from manage import app
ImportError: cannot import name 'app'
The way past this is to use flask.current_app instead of trying to import app.
In main.views, replace
from manage import app
with
from flask import current_app
then, instead of app.config[...], use current_app.config[...]
Related
Please help in solving this problem.
I have a project in Flask with a structure:
project
- main.py
- app
-- __init__.py
-- main
--- __init__.py
--- routes.py
-- auth
--- __init__.py
--- routes.py
--- forms.py
-- templates
--- index.html
app/main/routes.py
from flask import render_template
from app.main import bp
#bp.route('/')
def index():
return render_template('index.html')
app/main/init.py
from flask import Blueprint
bp = Blueprint('main', __name__)
from app.main import routes
app/init.py
from flask import Flask
from config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
from app.auth import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
main.py
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
I get an error when I start the application:
Could not build url for endpoint 'index'. Did you mean 'main.index' instead?
Tried to insert main.index. instead of index.html in combination with template_folder='../templates'. But then it doesn't find the template.
Everything was working fine, the imports have always worked and my project structure has not changed. I made some changes - adding fields & forms, and suddenly all the relative imports in my app/main/views.py stopped working. I reverted my changes - that did not work either. Help!
Update: So it runs fine from the command line with "flask run", but not in PyCharm. So I'm thinking it's PyCharm config issue. My config.py file has not changed at all, so I think it's here: PyCharm Run/Debug Config
I did not intentionally make ANY changes to the config.... so not sure what the next step is here. If anyone has advice on the config for this project, I would be grateful!
Here's the project structure. App, Auth and Main are shown as packages:
Project Structure
Here's the main app demo.py:
import os
from app import create_app, db
from app.models import Org, User, Role, DemoType, DemoReport, DemoRptQ, \
Demo, Question, Answer, Location
from flask_migrate import Migrate
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
migrate = Migrate(app, db)
#app.shell_context_processor
def make_shell_context():
return dict(db=db, Org=Org, User=User, Role=Role, Location=Location,
DemoType=DemoType, DemoReport=DemoReport, DemoRptQ=DemoRptQ, Demo=Demo,
Question=Question, Answer=Answer)
#app.cli.command()
def test():
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
Here's the app init.py
from flask import Flask
from flask_bootstrap import Bootstrap
from flask_mail import Mail
from flask_moment import Moment
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from config import config
bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
login_manager = LoginManager()
login_manager.login_view = 'auth.login'
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
bootstrap.init_app(app)
mail.init_app(app)
moment.init_app(app)
db.init_app(app)
login_manager.init_app(app)
from .main import main as main_blueprint
app.register_blueprint(main_blueprint)
from .auth import auth as auth_blueprint
app.register_blueprint(auth_blueprint, url_prefix='/auth')
return app
And the app/main package init.py:
from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors
from ..models import Permission
#main.app_context_processor
def inject_permissions():
return dict(Permission=Permission)
And finally the app/main views.py, where I am getting the error on the third line from .. import db
from datetime import datetime
from flask import render_template, session, redirect, url_for, flash
from .. import db
from ..models import User, Role, Location, Demo, Question, Answer, DemoType, DemoReport, DemoRptQ
from ..email import send_email
from . import main
from .forms import DashboardForm, EditProfileForm, EditProfileAdminForm, DemosForm, DemoForm
from .forms import QuestionsForm, QuestionForm, DemoTypesForm, DemoTypeForm, DemoReportsForm, DemoReportForm
from .forms import AnswerForm, AnswersForm, LocationsForm, LocationForm
from .forms import UsersForm
from flask_login import login_required, current_user
from ..decorators import admin_required
from wtforms.validators import DataRequired, Optional, Length
#main.route('/', methods=['GET', 'POST'])
def index():
form = DashboardForm()
if form.validate_on_submit():
btn = form.submit.raw_data[0]
if btn == 'Demos':
return redirect(url_for('.demos_list'))
elif btn == 'New Demo':
return redirect(url_for('.edit_demo', id=0))
elif btn == 'Login':
return redirect(url_for('auth.login'))
elif btn == 'Register':
return redirect(url_for('auth.register'))
return render_template('index.html', form=form, isauth=current_user.is_authenticated)
#main.route('/users')
def users_list():
form = UsersForm()
if form.validate_on_submit():
return redirect(url_for('.index'))
I found this answer in another post and it worked! In Pycharm Run/Debug Configs, uncheck "Add Content Roots to PYTHONPATH" and "Add Source Roots to PYTHONPATH". Don't understand why it broke or why it's fixed... but there's plenty of time for that later.
PyCharm Config Fix
I'm trying to write some unit tests for a flask application I made. The project is setup like this:
apiproject (parent folder containing everything)
/venv
run.py
requirements.txt
/project
__init__.py
/departments
__init__.py
routes.py
models.py
/users
__init__.py
routes.py
models.py
/tests
TestUsers.py
run.py:
from project import app
if __name__ == '__main__':
app.run(debug=True)
my actual app is created under project/init.py
from flask import Flask, jsonify, Response
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
import os
from dotenv import load_dotenv
from flask_cors import CORS
load_dotenv(verbose=False)
DB_URL = os.getenv("DATABASE_URL")
# initialize the application
app = Flask(__name__)
and in my TestUsers.py I have this:
import json
from project import app
import unittest
from dotenv import load_dotenv
load_env(verbose=False)
class TestUsers(unittest.TestCase):
def setUp(self):
self.app = app
self.url_prefix = prefix = os.getenv("URL_PREFIX")
self.client = self.app.test_client()
def test_index(self):
response = self.client.get(self.url_prefix + '/')
self.assertEqual(response.status_code, 200)
if __name__ == '__main__':
unittest.main()
When I run TestUsers.py, I get ModuleNotFoundError: No module named 'project'. I tried doing sys.path.append('../') and ../../ inside of TestUsers.py, but that didn't help.
inside TestUsers.py, before importing app:
https://stackoverflow.com/a/22737042/7858114
I think you need an init.py in your apiproject folder too.
I have structured my flask app in such a way that an app factory unifies all __init__.py files into one app object, like so:
app.py
tasks.py
/project/
__init__.py
routes/
__init__.py
auth_bp.py
register_bp.py
models/
__init__.py
user.py
base.py
app.py
from project import create_app
app = create_app()
project/__init__.py
from flask import Flask
def create_app():
from . import routes, models
app = Flask(__name__)
models.init_app(app)
routes.init_app(app)
return app
project/models/__init__,py
from base import db
def init_app(app):
db.init_app(app)
project/routes/__init__.py
from auth import auth_bp
from register import register_bp
def init_app(app):
app.register_blueprint(auth_bp)
app.register_blueprint(register_bp)
what I'm trying to wrap my head around is how to structure some background processes which depend on app.context(), like so:
project/tasks.py
import sys
sys.path.append('/path/to/root')
from app import app
def load_cache(track_and_features):
while True:
with app.app_context():
Upload_Track(track_and_features)
#app.route('/cache')
def cache(track_and_features):
executor.submit(load_cache, track_and_features)
return 'Ok'
the problem (I guess) occurs here, when I call cache(), in a module which imports the app object on its turn:
project/routes/auth_bp.py
from tasks import cache
#auth_bp.route("/callback/q")
def callback():
(...)
cache()
return redirect(url_for('register.homepage'))
I am getting the error:
File "app.py", line 6, in <module>
app = create_app()
File "/Users/me/Documents/Code/Apps/Production/project/__init__.py", line 20, in create_app
from . import routes
File "/Users/me/Documents/Code/Apps/Production/project/routes/__init__.py", line 1, in <module>
from auth import auth_bp
File "/Users/me/Documents/Code/Apps/Production/project/routes/auth.py", line 18, in <module>
from tasks import cache
File "/Users/me/Documents/Code/Apps/Production/tasks.py", line 4, in <module>
from app import app
File "/Users/me/Documents/Code/Apps/Production/app.py", line 6, in <module>
app = create_app()
File "/Users/me/Documents/Code/Apps/Production/project/__init__.py", line 20, in create_app
from . import models, routes, services
ImportError: cannot import name routes
How do I fix this?
Don't import app in routes. With an app factory, you do not have an app to register routes with, outside of the factory. Instead, use blueprints for all your views, and import the blueprint into the factory. You could still register your views with the app object inside the factory, but that's just not nearly as clean as just using a blueprint to register views with.
You already do this with dedicated init_app() functions, but your project/routes/tasks.py module doesn't follow this pattern. It too should be using a blueprint. You can share a blueprint between modules, if that simplifies your application.
The only point you actually create an app name, is to run the whole app, so for the WSGI server, tests or command-line tools.
I am using Flask for my web framework. I am having an issue with imports. I am not understanding why can't I import my variable when I declare it within my my_app/__init__.py:
from flask import Flask
from flask_login import LoginManager
from my_app.some_module.my_class.py import auth
app = Flask(__name__)
login_manager = LoginManager()
class Config:
def __init__(self):
pass
config = Config()
My conflictuous imports are present in my_app/some_module/my_class.py:
from flask import Blueprint
from my_app import login_manager # this one works fine
from my_app import config
auth = Blueprint('auth', __name__)
I run the app with run.py:
from my_app import app
app.run(debug=True)
I then get the error:
Traceback (most recent call last):
...
File ".../my_app/some_module/my_class.py", line 1, in <module>
from my_app import login_manager, config
ImportError: cannot import name 'config' from 'my_app' (.../my_app/__init__.py)
Project structure is:
my_app
+ __init__.py
some_module
+ __init__.py
+ my_class.py
+ run.py
You have a cyclic import: my_app.some_module -> my_app.some_module.my_class -> my_app.some_module.
You can fix this by moving both Config and config to a separate module my_app.some_module.config.
# my_app.some_module.my_config
class Config:
pass
config = Config()
# my_app.some_module.my_class
from .my_config import config
# my_app.some_module.__init__
from .my_config import config
from .my_class import MyClass
This means that every import does not depend on previous imports:
my_app.some_module
|-> my_app.some_module.my_class -> my_app.some_module.config
\-> my_app.some_module.my_config
Doing imports this way instead of moving the import for .my_class to the end of __init__.py is more robust. You can freely reorder the imports of .my_class and .my_config at the top of files.
The problem is that you have a cyclic dependency. By the time you import auth from my_app.some_module.my_class.py your config is not set yet. Try moving that import to the end of the my_app/__init__.py file like:
from flask import Flask
from flask_login import LoginManager
app = Flask(__name__)
login_manager = LoginManager()
class Config:
pass
config = Config()
from my_app.some_module.my_class.py import auth