Flask __init__.py structure on Heroku - flask

from .library.routes import library
2022-05-25T11:06:23.522123+00:00 app[web.1]: ImportError: attempted relative import with no known parent package
This is the log shown by heroku, and I encountered this problem again and again and again.
How could I solve this and deploy my site on heroku?
init.py
from flask import Flask
from .library.routes import library
from .chat.routes import chat
from .extensions import db, bcrypt, login, socketio
from .api.library_api import library_api
from .api.chat_api import chat_api
from .models.chat import user
from .user.routes import user_route
from .api.login_api import login_api
from .api.socket_api import socket_api
def create_app():
app = Flask(__name__)
app.secret_key = "Why would I show it to stackoverflow?"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///library.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
app.config["SQLALCHEMY_BINDS"] = {
'chat': "sqlite:///chat.sqlite3",
"library": "sqlite:///library.sqlite3"
}
db.init_app(app)
bcrypt.init_app(app)
login.init_app(app)
socketio.init_app(app)
login.blueprint_login_views = {
'chat': '/login',
'library': '/login'
}
with app.app_context():
db.create_all()
app.register_blueprint(library)
app.register_blueprint(chat)
app.register_blueprint(library_api)
app.register_blueprint(chat_api)
app.register_blueprint(user_route)
app.register_blueprint(login_api)
app.register_blueprint(socket_api)
return app
Procfile
web: gunicorn __init__:app --log-file=-
web: gunicorn --worker-class eventlet -w 1 __init__:app
This init.py is really hindering my development (especially when it comes to debugging due to it running 1000% slower than using a one big app.py) but I want to keep the blueprint approach for ease of organization

Related

How to determine flask_app name

Sorry if this is a bit basic but wanted to validate what my flask_app name would be that I set in my .env file when running locally.
I run my app using a wsgi.py file in root with the following contents:
from app import create_app, db
application = create_app()
if __name__ == '__main__':
application.run()
However I then have a app/init.py
import os
from config import Config
from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
#not sure if i mucked this up
db.init_app(app)
from app.main import main_blueprint
app.register_blueprint(main_blueprint)
return app
Which I run with flask run. Therefore is my app name “app” or “application” or even something else?
You want flask_app variable to be the name of the file which runs the app, so for you in your .env file it looks like you should have:
FLASK_APP = run.py
where run.py is the name of the file containing the first block of code in your question, assuming that your .env file is also in your root folder, let me know if that helps.

Flask - How to load database with config from Flask config?

My folder structure is the following:
- app.py
app
- __init__.py
- database.py
in app.py I have:
from app import create_app
app = create_app()
my init.py looks something like:
from flask import Flask
from app.database import db_session, init_db
db = SQLAlchemy()
def create_app():
myapp = Flask(__name__, static_folder='static', static_url_path='/static', template_folder="templates")
myapp.config.from_object('config.Config')
db.init_app(myapp)
migrate.init_app(myapp, db)
# loading blueprints
from app.core_bp import core_bp
myapp.register_blueprint(core_bp, url_prefix='/', template_folder="templates")
return myapp
and database.py looks like this
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///rapporteur.db')
db_session = scoped_session(sessionmaker(autocommit=False,autoflush=False,bind=engine))
That sqlite path is currently hardcoded to raporteur.db but it should be loaded from config, because I don't want it hardcoded, but unfortunately the flask app is not yet loaded. So how would I do this?
You can use flask-sqlalchemy and set the SQLALCHEMY_DATABASE_URI in the config file.
class Config:
SQLALCHEMY_DATABASE_URI = 'sqlite:///rapporteur.db'
then in your init.py
from youApp import Config
def create_app(config_class=Config)
app = Flask(__name__)
app.config.from_object(config_class)
db = SQLAlchemy()
db.init_app(app)
return app

Correctly Setup Celery with Flask-Application Factory Pattern/Gunicorn/Nginx/Supervisor

I have a task of updating every single row of a MySQL table but it's super slow. I rarely need to do it and only when I change something fundamental, but I thought this would be a great change to learn about multi threading. However all the examples and tutorials online go over some things and not others and I'm struggling to piece all the information together.
I know I need to make a celery process I just don't know if I'm doing it right. A lot of tutorials talk about dockerizing a redis environment without explaining how to do it so I thought I'd come here for some real human-to-human interaction to maybe help me feel less stupid about this.Here's my code so far
/website/__init__.py
from flask import Flask, appcontext_popped, render_template
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_migrate import Migrate
from flask_wtf import CSRFProtect
import logging
import celery
#Path Math
import sys
import os
from . import config
db:SQLAlchemy = SQLAlchemy()
migrate = Migrate()
csrf = CSRFProtect()
celery: celery.Celery
DB_NAME = "main"
def create_app(name):
#Flask Instance
app = Flask(__name__)
app.config.from_object(config.ProdTestConfig)
# logging stuff
#Database
db.init_app(app)
migrate.init_app(app, db)
csrf.init_app(app)
global celery
celery = make_celery(app)
with app.app_context():
db.create_all()
# Models and Blueprints here
from .helper_functions import migration_handling as mgh
#where you will find the thing I need to run async
app.before_first_request(mgh.run_back_check)
# log manager stuff
#error page handling
return app
def make_celery(app):
celery = celery.Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
I've read some other ways seem to fit a bit better like using:
celery = Celery(__name__, broker=Config.CELERY_BROKER_URL, result_backend=Config.RESULT_BACKEND)
Then in create_app() they run celery.conf.update(app.config). The issue with this is that I don't know how to setup a redis server on my linode machine hosting the site and my personal windows machine. I have redis pip installed. This is how the function I'm trying to run async looks:
#celery.task(name='app.tasks.campaign_pay_out_process')
def campaign_pay_out_process():
'''
Process Every Campaigns Pay
'''
campaign: Campaigns
for campaign in Campaigns.query.filter_by():
campaign.process_pay()
db.session.commit()
current_app.logger.info('Done Campaign Pay Out Processing')
I'm running gunicorn off of supervisor because restarting is super easy and ridding my life of super long linux commands to start a process has been great. I know this is the command for celery: celery -A celery_worker.celery worker --pool=solo --loglevel=info and I'd love to know how to include that in my work flow. Here's my supervisor config:
[program:paymentwebapp]
directory=/home/sai/paymentWebApp
command=/home/sai/paymentWebApp/venv/bin/gunicorn --workers 1 --threads 3 wsgi:app
user=sai
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stderr_logfile=/var/log/paymentwebapp/paymentwebapp.err.log
stdout_logfile=/var/log/paymentwebapp/paymentwebapp.out.log
Here's my flask config right now:
from os import environ, path
from dotenv import load_dotenv
DB_NAME = "main"
class Config:
"""Base config."""
#SESSION_COOKIE_NAME = environ.get('SESSION_COOKIE_NAME')
MAX_CONTENT_LENGTH = 16*1000*1000
RECEIPT_FOLDER = '../uploads/receipts'
IMPORT_FOLDER = 'uploads/imports'
UPLOAD_FOLDER = 'uploads'
EXPORT_FOLDER = '/uploads/exports'
UPLOAD_EXTENSIONS = ['.jpg', '.png', '.pdf', '.csv', '.xls', '.xlsx']
STATIC_FOLDER = 'static'
TEMPLATES_FOLDER = 'templates'
class ProdConfig(Config):
basedir = path.abspath(path.dirname(__file__))
load_dotenv('/home/sai/.env')
env_dict = dict(environ)
FLASK_ENV = 'production'
DEBUG = False
TESTING = False
SQLALCHEMY_DATABASE_URI = environ.get('PROD_DATABASE_URI')
SECRET_KEY = environ.get('SECRET_KEY')
SERVER_NAME = environ.get('SERVER_NAME')
SESSION_COOKIE_SECURE = True
WTF_CSRF_TIME_LIMIT = 600
#Uploads
class DevConfig(Config):
basedir = path.abspath(path.dirname(__file__))
load_dotenv('C:\saiscripts\intercept_branch\Payment Web App Project\.env')
env_dict = dict(environ)
FLASK_ENV = 'development'
DEBUG = True
SQLALCHEMY_DATABASE_URI = environ.get('DEV_DATABASE_URI')
SECRET_KEY = environ.get('SECRET_KEY')
class ProdTestConfig(DevConfig):
'''
Developer config settings but production database server
'''
SQLALCHEMY_DATABASE_URI = environ.get('PROD_DATABASE_URI')
if __name__ == '__main__':
print(environ.get('SQLALCHEMY_DATABASE_URI'))
This is where I copied some code from a tutorial because I'm supposed to make a celery worker:
#!/usr/bin/env python
import os
#from app import create_app, celery
from website import create_app
app = create_app()
app.app_context().push()
from website import celery

flask NoAppException but flask run works

I have the following structure:
app_dir/
| myapi/
| __init__.py
| myapi_app.py
where myapi_app.py is
from myapi import create_app, db
app = create_app()
and myapi/__init__.py is
import logging
import os
from logging.handlers import RotatingFileHandler
from flask import Flask, request, current_app
from flask_sqlalchemy import SQLAlchemy
from myapi.config import Config
db = SQLAlchemy()
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
db.init_app(app)
...
return app
When I set FLASK_APP=myapi_app.py and run flask run from the app_dir directory, the flask service starts. However, when I make a request, I get the following error: flask.cli.NoAppException: Could not import "myapi_app". Where am I going wrong?
Your problem is that you are setting $FLASK_APP to the file in which the app variable is stored, you should instead set it to the python object path, e.g.
FLASK_APP=myapi_app:app
However, this is not necessary, as you could also just do:
FLASK_APP=myapi
as Flask will look for a create_app function in the package on its own.

Flask - Attempted relative import in non-package

Following this tutorial on how to structure a Flask app, I have:
project/
__init__.py
app.py
models/
__init__.py
base.py
base.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
models/__init__.py
from .base import db
def init_app(app):
db.init_app(app)
project/__init__.py
from flask import Flask
def create_app()
from . import models, routes, services
app = Flask(__name__)
models.init_app(app)
# routes.init_app(app)
# services.init_app(app)
return app
finally, in app.py, I try to run it:
from . import create_app
app = create_app()
if __name__ == '__main__':
app.run(use_reloader=True, threaded=True, debug=True)
but I'm getting the error:
from . import create_app
ValueError: Attempted relative import in non-package
Am I building it right, what am I doing wrong?
I guess you are running your program by:
python project/app.py
In this case, you are not treat your "project" as a python package, which will raise the error you got. Instead, you can run your project with:
FLASK_APP=project.app flask run