how to access app object in other files of flask app - python

# flask packages
import jwt
from flask import Flask
from flask_restful import Api
from flask_mongoengine import MongoEngine
from flask_jwt_extended import JWTManager
import logging
# local packages
import models
from api.routes import create_routes
# external packages
import os
# default mongodb configuration
default_config = {'MONGODB_SETTINGS': {
'db': 'blog_db',
'host': 'localhost',
'port': 27017}
}
def get_flask_app(config: dict = None):
"""
Initializes Flask app with given configuration.
Main entry point for wsgi (gunicorn) server.
:param config: Configuration dictionary
:return: app
"""
# init flask
app = Flask(__name__)
# # configure app
# config = default_config if config is None else config
# app.config.update(config)
# load config variables
if 'MONGODB_URI' in os.environ:
app.config['MONGODB_SETTINGS'] = {'host': os.environ['MONGODB_URI'], 'retryWrites': False}
if 'JWT_SECRET_KEY' in os.environ:
app.config['JWT_SECRET_KEY'] = os.environ['JWT_SECRET_KEY']
app.config['JWT_BLACKLIST_ENABLED'] = True
app.config['JWT_BLACKLIST_TOKEN_CHECKS'] = ['access', 'refresh']
# File upload configs
app.config['PROFILE_FOLDER'] = '/images/profiles'
app.config['PROFILE_FOLDER'] = '/images/posts'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
app.config['ALLOWED_EXTENSIONS'] = set(['png', 'jpg', 'jpeg', 'gif'])
# init api and routes
api = Api(app=app)
create_routes(api=api)
# init mongoengine
db = MongoEngine(app=app)
# init jwt manager
jwt = JWTManager(app=app)
# #jwt.token_in_blocklist_loader
# def check_if_token_in_blacklist(decrypted_token):
# jti = decrypted_token['jti']
# return models.RevokedTokens.is_jti_blacklisted(jti)
return app
if __name__ == '__main__':
# Main entry point when run in stand-alone mode.
app = get_flask_app()
app.run(debug=True)
I am trying to use app object in the file in different folder utilities.py
import os
import sys
from werkzeug.utils import secure_filename
from flask import jsonify
from run import app
class Utilities:
FILE_ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif'])
#staticmethod
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in Utilities.FILE_ALLOWED_EXTENSIONS
#staticmethod
def upload_files(file, filename, foldername):
try:
print(">>>>>>>>>" + foldername + filename, file=sys.stdout)
filename = secure_filename(filename)
file.save(os.path.join(app.root_path, foldername, filename))
resp = jsonify({'message': 'File successfully uploaded'})
resp.status_code = 201
return resp
except Exception as e:
print(">>>>>>>>>" + str(e), file=sys.stdout)
resp = jsonify({'message': 'File upload failed'})
resp.status_code = 400
return resp
but getting below error :
ImportError: cannot import name 'create_routes' from partially initialized module 'api.routes' (most likely due to a circular import) (D:\Python\Projects\XXXX\api\routes.py)
enter image description here

Related

Using data from python Web-socket inside flask application

I came across a problem where I want to consume data from a python Websocket named truedata-ws inside my flask application, I had tried different ways but, I am not able to succeed. Please help me out for the same below are my main script file and the file for the connection to the Websocket
Main.py file
import sqlalchemy
from flask import Flask, url_for
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_mail import Mail
from flask_restful import Api
from flask_sock import Sock
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine
from ryj_bhav.Config import Config
from truedata_ws.websocket.TD import TD
import logging
bcrypt = Bcrypt()
login_manager = LoginManager()
login_manager.login_view = 'users.login'
login_manager.login_message_category = 'info'
db = SQLAlchemy()
mail = Mail()
api = Api()
sock = Sock()
Gold_Onn = 55000
Silver_Onn = 65000
#sock.route('/echo')
def echo():
while True:
username = 'test'
password = 'test'
realtime_port = 8084
url = 'push.truedata.in'
symbols = ["SYMBOL-I", "SYMBOL-II"]
td_obj = TD(username, password, live_port=realtime_port, url=url, log_level=logging.DEBUG,
log_format="%(message)s")
#td_obj.trade_callback
def strategy_callback(symbol_id, tick_data):
print(f'Trade update > {tick_data}')
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
bcrypt.init_app(app)
login_manager.init_app(app)
db.init_app(app)
mail.init_app(app)
sock.init_app(app)
from ryj_bhav.routes import routes
from ryj_bhav.routes import LiveRateAPI
api.add_resource(LiveRateAPI, '/live-bhav')
api.init_app(app)
app.register_blueprint(routes)
return app
true-data-ws.py (websocket file)
from truedata_ws.websocket.TD import TD
import time
import logging
from datetime import date
username = 'test'
password = 'test'
realtime_port = 8084
url = 'push.truedata.in'
symbols = ["SYMBOL-I", "SYMBOL-II"]
print('About To Start')
td_obj = TD(username, password, live_port=realtime_port, url=url, log_level=logging.DEBUG, log_format="%(message)s")
# td_obj = TD(username, password, live_port=realtime_port, url=url, historical_api=False)
print('\n')
print('Starting Real Time Feed....')
req_ids = td_obj.start_live_data(symbols)
live_data_objs = {}
time.sleep(2)
for req_id in req_ids:
print('my req ids', req_id)
print(f'touchlinedata -> {td_obj.touchline_data[req_id]}')
#td_obj.trade_callback
def strategy_callback(symbol_id, tick_data):
print('My Symbol id',tick_data.get('ltp'))
# print(f'Trade update > {tick_data}')
# #td_obj.bidask_callback
# def new_bidask(symbol_id, tick_data):
# print(f"BidAsk update > {tick_data}")
while True:
time.sleep(120)
I had tried this solution and also tried to run it from my main file
run.py
from ryj_bhav import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
I had also tried multithreading but did not got succeed in any of the above tried solution.

send filename and file to python api for upload image

followings are my code for server and client where i want to pass filename in server api so that server and save the image as sender filename.
server.py
from flask import Flask
from flask_restful import Resource, Api, reqparse
import werkzeug
app = Flask(__name__)
api = Api(app)
class UploadImage(Resource):
def post(self):
parser = reqparse.RequestParser()
#parser.add_argument('FNAME', required=True)
parser.add_argument('file', type=werkzeug.datastructures.FileStorage, location='files')
args = parser.parse_args()
imageFile = args['file']
#filename = args['FNAME']
#print(filename)
imageFile.save('test.jpg')
api.add_resource(UploadImage, '/uploadimage')
if __name__ == '__main__':
#app.run() # run our Flask app
from waitress import serve
print("Running....")
serve(app,host="0.0.0.0",port=8080)
print("Stopped....")
client.py
import requests
import json
dfile = open("test.jpg", "rb")
url = "http://127.0.0.1:8080/uploadimage"
test_res = requests.post(url, files = {"file": dfile})
print(test_res)
if test_res.ok:
print(" File uploaded successfully ! ")
else:
print(" Please Upload again ! ")
The commented-out code you had would work with a small tweak, but if you're going by the standard Flask-RESTful documentation, it doesn't mention that you need to set the location on the argument.
With werkzeug-2.1.0, the flask-restful reqparse now has a 'bug' where if reqparse attempts to access an argument using the default location parameter, it will raise an exception on the server side. See this Github issue for more information.
So you need to add your filename (or FNAME or whatever) argument, but with location="form" specified like in the following Flask app that will accept an image in the file field, and a filename field to specify the name to save it as.
from flask import Flask
from flask_restful import Resource, Api, reqparse
import werkzeug
app = Flask(__name__)
api = Api(app)
upload_parser = reqparse.RequestParser(bundle_errors=True)
upload_parser.add_argument(
'file',
required=True,
type=werkzeug.datastructures.FileStorage,
location='files'
)
# note that location="form" is specified
upload_parser.add_argument(
"filename",
required=True,
type=str,
location="form"
)
class UploadImage(Resource):
def post(self):
args = upload_parser.parse_args()
image = args.file
image.save(args.filename)
api.add_resource(UploadImage, '/uploadimage')
if __name__ == '__main__':
app.run()
# you can add back your waitress.serve stuff here
# but I didn't want to bother in my test environment
And now I can hit it with a request and have it save my image:
curl http://localhost:5000/uploadimage \
-F "filename=my-image.png" \
-F "file=#/path/to/image.png"

Flask "send_from_directory" works in local, but doesn't in remote

On my flask app, I upload a file, save it to a directory and then send it back as attachment.
When I run my code on "debug" mode on my local machine using VSCode, it works as expected. But when I upload the app to the remote server, I always get a "404" error.
Any idea of what I am missing?
#import Flask
from flask import Flask, request, send_from_directory
import json
import os
app = Flask(__name__)
UPLOAD_FOLDER_MR_PROPER = './tmp/mrProper/'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER_MR_PROPER
#app.route('/')
def index():
return 'index'
#app.route('/mrProper', methods=['POST'])
def handler_mrProper():
import shortuuid
uploaded_file = request.files['file']
tmp_name = shortuuid.uuid()
_, tmp_ext = uploaded_file.filename.rsplit(".", 1)
tmp_filename = tmp_name + "." + tmp_ext
if uploaded_file.filename != '':
uploaded_file.save(app.config['UPLOAD_FOLDER'] + tmp_filename)
sp = os.path.join(app.instance_path, app.config['UPLOAD_FOLDER'] )
# SOME IRRELEVANT PROCESSING
return send_from_directory( app.config['UPLOAD_FOLDER'],
tmp_filename,
mimetype = request.files["file"].content_type,
as_attachment = True,
attachment_filename = uploaded_file.filename,
cache_timeout=0)
if __name__ == '__main__':
app.run(debug=True)
.htaccess solved the problem.
Two issues here:
Route: Must be absolute path: UPLOAD_FOLDER_MR_PROPER = '/var/...../tmp/mrProper/'
.htaccess rewrite: Adding "/app/tmp/mrProper/" solved it.

Flask testing with pytest, ENV is set to production?

I have built a flask app and i would like to create a test suite. Reading around it looks like pytest is the way to go; however, I am finding it very difficult to understand how to get going, I have looked at https://flask.palletsprojects.com/en/2.0.x/testing/ but am struggling to relate it to my app.
my project has a run.py at its base:
from wahoo_connect import init_app, db
from flask_migrate import Migrate
#run the app
app = init_app()
migrate = Migrate(app, db)
this is run using flask run and the .flaskenv sets the mode
FLASK_APP=run.py
#FLASK_ENV=production
FLASK_ENV=development
I have an application factory set up:
"""Main entry point into App"""
#import libraries
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
from flask_mail import Mail
#from flask_caching import Cache
from flask_session import Session
from os import path, mkdir
import logging
from logging.handlers import SMTPHandler, RotatingFileHandler
"""Flask Global Variables"""
#database connection
db = SQLAlchemy()
migrate = Migrate()
#login manager
login = LoginManager()
login.login_view = 'auth_bp.login'
login.login_message = 'Please log in to access this page.'
login.login_message_category = "info"
#email
mail = Mail()
#cache
#cache = Cache()
#session
sess = Session()
#initialise app
def init_app():
"""Initialize the core application."""
app = Flask(__name__)
print(app.config['ENV'])
if app.config['ENV'] == 'production':
app.config.from_object('wahoo_connect.config.ProductionConfig')
elif app.config['ENV'] == 'development':
app.config.from_object('wahoo_connect.config.DevelopmentConfig')
elif app.config['ENV'] == 'testing':
app.config.from_object('wahoo_connect.config.TestingConfig')
# Initialize Plugins
db.init_app(app)
migrate.init_app(app, db)
login.init_app(app)
mail.init_app(app)
# cache.init_app(app)
sess.init_app(app)
with app.app_context():
# Import and Register Blueprints
from wahoo_connect.errors.views import errors_bp
from wahoo_connect.auth.views import auth_bp
from wahoo_connect.profile.views import profile_bp
from wahoo_connect.wahoo.views import wahoo_bp
from wahoo_connect.home.views import home_bp
app.register_blueprint(errors_bp)
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(profile_bp)
app.register_blueprint(wahoo_bp, url_prefix='/wahoo')
app.register_blueprint(home_bp)
if not app.debug:
#log to email
if app.config['MAIL_SERVER']:
auth = None
if app.config['MAIL_USERNAME'] or app.config['MAIL_PASSWORD']:
auth = (app.config['MAIL_USERNAME'], app.config['MAIL_PASSWORD'])
secure = None
if app.config['MAIL_USE_TLS']:
secure = ()
mail_handler = SMTPHandler(
mailhost=(app.config['MAIL_SERVER'], app.config['MAIL_PORT']),
fromaddr=app.config['MAIL_USERNAME'],
toaddrs=app.config['ADMINS'],
subject='Error in Wahoo-Connect',
credentials=auth, secure=secure)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
#log to file - heroku
if app.config['LOG_TO_STDOUT']:
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
app.logger.addHandler(stream_handler)
else:
logdir = path.dirname(app.instance_path) + '/logs'
if not path.exists(logdir):
mkdir(logdir)
file_handler = RotatingFileHandler(logdir + '/wahoo-connect.log',
maxBytes=10240, backupCount=10)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s '
'[in %(pathname)s:%(lineno)d]'))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Wahoo-Connect Startup')
return app
from wahoo_connect import models
Everything works and I can run the app on a production server. I am trying to get started with pytest and have set up conftest.py:
import pytest
from wahoo_connect import init_app
from wahoo_connect.models import User
#pytest.fixture(scope="session")
def app():
app = init_app()
return app
this always runs the app in production mode, how do I get it to run in testing mode so that it uses the correct config from config.py
"""Flask configuration."""
from os import environ, path
from dotenv import load_dotenv
from datetime import timedelta
#basedir = path.abspath(path.dirname(__file__))
basedir = path.dirname(path.dirname(path.abspath(__file__)))
load_dotenv(path.join(basedir, '.env'))
class Config(object):
"""Base config."""
DEBUG = False
TESTING = False
SECRET_KEY = environ.get('SECRET_KEY') or 'topsecretkey'
STATIC_FOLDER = 'static'
TEMPLATES_FOLDER = 'templates'
SESSION_COOKIE_SECURE = True
#Database
SQLALCHEMY_DATABASE_URI = environ.get('DATABASE_URL') or \
'sqlite:///' + path.join(basedir, 'app.db')
#fix for heroku postgres db
if SQLALCHEMY_DATABASE_URI.startswith("postgres://"):
SQLALCHEMY_DATABASE_URI = SQLALCHEMY_DATABASE_URI.replace("postgres://", "postgresql://", 1)
SQLALCHEMY_TRACK_MODIFICATIONS = False
#Wahoo
WAHOO_CLIENT_ID=environ.get('WAHOO_CLIENT_ID')
WAHOO_CLIENT_SECRET=environ.get('WAHOO_CLIENT_SECRET')
WAHOO_CLIENT_REDIRECT=environ.get('WAHOO_CLIENT_REDIRECT')
#Email
MAIL_SERVER = environ.get('MAIL_SMTP_SERVER')
MAIL_PORT = int(environ.get('MAIL_SMTP_PORT') or 25)
MAIL_USERNAME = environ.get('MAIL_SMTP_LOGIN')
MAIL_PASSWORD = environ.get('MAIL_SMTP_PASSWORD')
MAIL_USE_TLS = environ.get('MAIL_USE_TLS') is not None
ADMINS = ['martyndwheeler#gmail.com']
#Logging
LOG_TO_STDOUT = environ.get('LOG_TO_STDOUT') or None
# Flask-Caching related configs
CACHE_TYPE = 'FileSystemCache'
CACHE_DIR = environ.get('CACHE_DIR') or None
CACHE_DEFAULT_TIMEOUT = 300
CACHE_THRESHOLD = 100
# Flask-Session related configs
SESSION_PERMANENT = False
PERMANENT_SESSION_LIFETIME = timedelta(minutes=30)
SESSION_USE_SIGNER = True
SESSION_TYPE = "filesystem"
SESSION_FILE_DIR = environ.get('SESSION_FILE_DIR')
SESSION_FILE_THRESHOLD = 100
class ProductionConfig(Config):
pass
class DevelopmentConfig(Config):
DEBUG = True
SESSION_COOKIE_SECURE = False
class TestingConfig(Config):
TESTING = True
SESSION_COOKIE_SECURE = False
If there is a good tutorial that I have missed I'd be pleased to hear.
What is Dotenv
Use Dotenv package
#test.py
from os import environ
print(environ.get("ENV_VAR")) # Output : test
#.env
ENV_VAR=test
How to use it in youre case
Option 1
You can use this to store an Boolean in .env file and read it to define wich mode you are running. be careful as env variables get read as string. if you wanna use boolean you need to parse them from the string.
Option 2
An other option is to store in env file which config you wanna use and make an if else tree in python script:
if os.environ.get("CONFIG") == "1":
app.config.from_object("config.conf1")
elif os.environ.get("CONFIG") == "2":
app.config.from_object("config.conf2")
else:
app.config.from_object("config.default")
Why use Dotenv
The advantage of using environment variables is that you can ignore them in git and every time the server is seetup in linux or docker all settings can be managed from one file. also does the standart server admin know bash script and env files but not necesseraly python.

400 Bad Request while POSTing json to Flask on openshift

I have read all related SO questions on this but I still keep encountering this error(400 - Bad Request) when posting json to my Flask app running on RedHat's openshift cloud platform.
This is my code:
flaskapp.py
import os
from datetime import datetime
from flask import Flask, request, flash, url_for, redirect, \
render_template, abort, send_from_directory
app = Flask(__name__)
app.config.from_pyfile('flaskapp.cfg')
#app.route('/')
def index():
return render_template('index.html')
#app.route('/<path:resource>')
def serveStaticResource(resource):
return send_from_directory('static/', resource)
#app.route("/test")
def test():
return "<strong>It's Alive!</strong>"
#app.route('/mine', methods=['POST'])
def mine():
content = request.get_json(force=True)
print content
return "Success!\n"
if __name__ == '__main__':
app.run(debug=True)
This is how my app.py looks like
#!/usr/bin/env python
# This file may be used instead of Apache mod_wsgi to run your python
# web application in a different framework. A few examples are
# provided (cherrypi, gevent), but this file may be altered to run
# whatever framework is desired - or a completely customized service.
#
import imp
import os
import sys
try:
virtenv = os.path.join(os.environ.get('OPENSHIFT_PYTHON_DIR','.'), 'virtenv')
python_version = "python"+str(sys.version_info[0])+"."+str(sys.version_info[1])
os.environ['PYTHON_EGG_CACHE'] = os.path.join(virtenv, 'lib', python_version, 'site-packages')
virtualenv = os.path.join(virtenv, 'bin','activate_this.py')
if(sys.version_info[0] < 3):
execfile(virtualenv, dict(__file__=virtualenv))
else:
exec(open(virtualenv).read(), dict(__file__=virtualenv))
except IOError:
pass
#
# IMPORTANT: Put any additional includes below this line. If placed above this
# line, it's possible required libraries won't be in your searchable path
#
#
# main():
#
if __name__ == '__main__':
application = imp.load_source('app', 'flaskapp.py')
port = application.app.config['PORT']
ip = application.app.config['IP']
app_name = application.app.config['APP_NAME']
host_name = application.app.config['HOST_NAME']
fwtype="wsgiref"
for fw in ("gevent", "cherrypy", "flask"):
try:
imp.find_module(fw)
fwtype = fw
except ImportError:
pass
print('Starting WSGIServer type %s on %s:%d ... ' % (fwtype, ip, port))
if fwtype == "gevent":
from gevent.pywsgi import WSGIServer
WSGIServer((ip, port), application.app).serve_forever()
elif fwtype == "cherrypy":
from cherrypy import wsgiserver
server = wsgiserver.CherryPyWSGIServer(
(ip, port), application.app, server_name=host_name)
server.start()
elif fwtype == "flask":
from flask import Flask
server = Flask(__name__)
server.wsgi_app = application.app
server.run(host=ip, port=port)
else:
from wsgiref.simple_server import make_server
make_server(ip, port, application.app).serve_forever()
And this how am posting the data:
curl -X POST -H "application/json" -d '{"key":"val"}'
https://python-bonga.rhcloud.com/mine
N/B: This works fine on localhost
I found that a POST using curl without specifying the Content-Type defaults to sending Content-Type application/x-www-form-urlencoded
http://curl.haxx.se/docs/httpscripting.html#POST
And if the (different) mimetype exists in Flask, then the json data becomes unavailable; hence request.get_json(force=True) fails.
I therefore changed my code to look for form-data first before anything else
if request.form:
content = [item for item in request.form]
print "Content:", ''.join(content)
else:
content = request.get_json(force=True)
print "Content:", content

Categories

Resources