I have a question regarding the flask_track_usage module.
All my blueprints should have the Trackusage function included.
Unfortunately i didn't find a way to solve my problem.
Why isn't it possible to simply use the flask.current_app?
route.py
import datetime
from uuid import uuid4
from flask import Blueprint, session, render_template, url_for, flash, redirect, current_app, request, jsonify
from flask_template.main.utils import my_func
import os
import json
from flask_track_usage import TrackUsage
from flask_track_usage.storage.printer import PrintWriter
from flask_track_usage.storage.output import OutputWriter
main = Blueprint('main', __name__)
t = TrackUsage(current_app, [
PrintWriter(),
OutputWriter(transform=lambda s: "OUTPUT: " + str(s))
])
#t.include
#main.before_request
def session_management():
now = datetime.datetime.now()
session_lifetime = current_app.config['SESSION_DURATION']
# Create session, if not already existing
if session.get('session_ID') is None:
# Initiate session, set a random UUID as Session ID
session['session_ID'] = str(uuid4())
session.permanent = True # will expire after 30 minutes of inactivity
session['timeout'] = False
print(f'Initated session with ID:', session.get('session_ID'))
return redirect(url_for('main.index'))
else:
try:
last_active = session.get('last_active')
delta = now - last_active
if delta.seconds > 1740:
print(f'Note: Session lifetime less than one minute. Expires in:',
session_lifetime - delta.seconds, 'sec')
if delta.seconds > session_lifetime:
session['last_active'] = now
session['timeout'] = True
print(f'Your session has expired after 30 minutes, you have been logged out (files are deleted).')
return redirect(url_for('main.logout'))
except:
pass
try:
session['last_active'] = now
except:
pass
#main.route('/')
def index():
return redirect(url_for('main.home'))
#main.route('/home')
def home():
return render_template('home.html', title='home', subheader='Template Main Page')
__init__.py
from flask import Flask
from flask_template.config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
from flask_template.sample_extension.routes import sample_extension
from flask_template.main.routes import main
from flask_template.errors.handlers import errors
app.register_blueprint(sample_extension)
app.register_blueprint(main)
app.register_blueprint(errors)
return app
Config
import os
import json
from datetime import timedelta
with open(os.path.join(os.getcwd(), 'etc', 'app_config.json')) as config_file:
config = json.load(config_file)
class Config:
SECRET_KEY = config.get('SECRET_KEY')
SESSION_DURATION = 1800 # 30 minutes for delete function
PERMANENT_SESSION_LIFETIME = timedelta(minutes=30) # session lifetime
root_dir = os.path.join(os.path.realpath('.'), 'flask_template')
# Path to template to illustrate download functionality
TEMPLATE_FOLDER = os.path.join(root_dir, 'sample_extension', 'assets', 'template')
TRACK_USAGE_USE_FREEGEOIP = False
TRACK_USAGE_INCLUDE_OR_EXCLUDE_VIEWS = 'include'
run.py
from flask_template import create_app
from flask_track_usage import TrackUsage
from flask_track_usage.storage.printer import PrintWriter
from flask_track_usage.storage.output import OutputWriter
app = create_app()
if __name__ == '__main__':
app.run(ssl_context=('******'),
host='0.0.0.0',
port=5000,
debug=True)
error
RuntimeError: Working outside of application context.
There are several global Flask variables such as current_app and g that can be accessed only while the application is running (more about them in the Flask Application Context documentation entry). Using them outside the application context raises RuntimeError.
You can instantiate TrackUsage without parameters in your routes.py module:
track_usage = TrackUsage()
#track_usage.include
#main.before_request
def session_management():
...
And then you can import it in your __init__.py module and apply to your application instance:
from flask import Flask
from flask_template.config import Config
from flask_track_usage.storage.printer import PrintWriter
from flask_track_usage.storage.output import OutputWriter
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(Config)
from flask_template.sample_extension.routes import sample_extension, track_usage
from flask_template.main.routes import main
from flask_template.errors.handlers import errors
track_usage.init_app(app, [
PrintWriter(),
OutputWriter(transform=lambda s: "OUTPUT: " + str(s)),
])
app.register_blueprint(sample_extension)
app.register_blueprint(main)
app.register_blueprint(errors)
return app
I have not found this solution in the Flask-Track-Usage documentation but it is a common interface for Flask extentions. It allows to instantiate an extension in one module and connect it to Flask application in main module.
Related
Writting UniTTest For Flask Application
I have a simple Flask Application below , flask application will work perfectly fine without any issues
import sys , os , os.path , time , datetime , json , logging, warnings
from os import listdir
from os.path import isfile, join
from flask_wtf.csrf import CSRFProtect
from flask import Flask
from flask import render_template
from flask import request
from datetime import datetime
from logging import FileHandler
from logging import Formatter
# --> Required Host and Env
_cloudhost='dev.net'
_cloudenv='dev'
_portNumber=4444
#CRF Compliant / (.)
app = Flask(__name__)
csrf = CSRFProtect()
csrf.init_app(app)
#app.route('/')
#app.route('/index')
def index():
project = "CFTP - TBRP & TBLP "
framework = "Publish Framework"
version = '0.1'
hostname = os.popen("echo $(hostname)").read().split('\n')[0]
return render_template('index.html', title=project , description=f'{project} : {framework} v - {version}' , hostname=hostname , logFile=readlogs(), get_env=_cloudenv)
app.run(host=_cloudhost, port=_portNumber)
UnitTest Function . I am struggling to understand on how i can create unit test cases for flask application. Inside my unittest file which i created , i was wondering if i am doing this right .
1 -> To test the csrf if that i included above and also on how i can test my index page can result as pass
test_flask.py
import unittest , sys , tempfile, os , json , shutil
from unittest import mock
from subprocess import Popen, PIPE
import logging
with mock.patch.dict(os.environ, {'PROJECT_FOLDER':'CitiFTP Reports','RPM_ENVIRONMENT': 'DEV', 'HOST_NAME': 'sd-nzvp-czog.nam.nsroot.net', 'USER': 'citiftptabhyper','TABLEAU_PUBLISH_TYPE':'TABCMD','TABCMD_PATH':'/home/citiftptabhyper/tabcmd','CYBERARK_TYPE':'DYNAMIC','JOB_TYPE':'workbook_TP','JOB_FILE':'publish_workbook_TP','RESTAPI_LOG_TYPE':'TP'}):
sys.path.insert(2, 'C:/Users/mm13854/Desktop/FileCopy_Dec_122/cftp_tableau_filecopy/deploy/src')
sys.path.insert(1, 'C:/Users/mm13854/Desktop/FileCopy_Dec_122/cftp_tableau_filecopy/deploy/app')
import env_conf as conf
import run_flask as flk_app
from run_flask import app
class test_tbrp_case(unittest.TestCase):
def setUp(self):
self.ctx = app.app_context()
self.ctx.push()
self.client = app.test_client()
def tearDown(self):
self.ctx.pop()
def test_home(self): ## Fail
response = self.client.post("/index", data={"title": "CFTP - TBRP & TBLP "})
assert response.status_code == 200
## test flask port used -- PASS
def test_port(self):
self.assertEqual(flk_app._portNumber,4444)
## Test host is returning the same value -- PASS
def test_host(self):
self.assertEqual(flk_app._cloudhost,conf.FLASK_CONFIGURATION.get('ENV_URL'))
def test_csrf(self):
pass
if __name__=='__main__':
unittest.main()
This is my main.py file :
from flask_redis import FlaskRedis
from controllers.utils import redis_conn # get Redis URL
import connexion
BASE_PATH = "/"
def create_app(*specs):
_app = connexion.App(__name__)
for s in specs:
logger.info("Adding specs {}".format(s))
_app.add_api(s, validate_responses=True)
return _app
app = create_app("specs.yaml")
rd_app = app.app
rd_app.config['REDIS_URL'] = redis_conn()
redis_client = FlaskRedis(rd_app)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000, debug = True)
It seems the Redis has issue and producing this error :
ImportError: cannot import name 'redis_client' from partially
initialized module 'main' (most likely due to a circular import)
I can't find any tutorial that use connexion with Redis.
Example of usage get_fruit.py:
from main import redis_client
def get_fruit(colour, shape, taste):
hash_name = rd_collections[colour+'_'+shape]
key_name = '{}:{}'.format(hash_name, taste)
response_redis = redis_client.get(name=key_name)
if response_redis is None:
result = get_fruit_name(colour, shape, taste)
logger.debug("Updating Redis by adding {}".format(location_id))
redis_client.set(name=key_name, value=json.dumps(result['fruit_id']), ex=60*60)
result = OrderedDict({'Result': result})
return result
else:
...
UPDATE:
Attempted as suggested :
def create_app(*specs):
"""
Running apps using connexion
"""
_app = connexion.App(__name__)
rd_app = _app.app
rd_app.config['REDIS_URL'] = redis_conn()
rd_client = FlaskRedis(rd_app)
for s in specs:
logger.info("Adding specs {}".format(s))
_app.add_api(s, validate_responses=True)
return _app, rd_client
app, redis_client = create_app("specs.yaml")
But still producing the same error.
The standard way, which avoids the circular import, is the following one.
Create a config.py file with your configuration.
from controllers.utils import redis_conn # get Redis URL
class MyConfig(object):
REDIS_URL = redis_conn()
Create a wsgi.py file. This will be the starting point of your app.
from config import MyConfig
import app_factory
app = app_factory.create_app(MyConfig)
if __name__ == "__main__":
with app.app_context():
app.run()
Create an app_factory.py file with the App Factory pattern:
redis_client = FlaskRedis()
def create_app(config):
app = Flask(__name__)
app.config.from_object(config)
redis_client.init_app(app)
return app
Create a file routes.py with your routes:
from app_factory import redis_client
#bp.route('/')
def index():
return redis_client.get('potato')
How can I make #celery.task available on user resources package?
I'm new to python and confused about the "circular imports error" can somebody explain how it works? and how to handle this kind of errors in flask application. This is the part where I always get stuck.
This is my project current folder structure
code
|_resources
| |_user.py
|
|_utils
| |_flask_celery.py
|
|_flask_app.py
--- SOURCE CODE ---
flask_app.py
from flask import Flask
from flask_cors import CORS
from flask_restful import Api
from util.flask_celery import make_celery
from routes.endpoint import urls
from resources.user import Users
app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql:///username:StrongPassword#localhost:3306/db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['CELERY_BROKER_URL'] = 'amqp//admin:StrongPassword#localhost:5672'
app.config['CELERY_RESULT_BACKEND'] = 'db+mysql:///username:StrongPassword#localhost:3306/db'
app.config['PROPAGATE_EXCEPTIONS'] = True
api = Api(app)
celery = make_celery(app)
url = urls()
api.add_resource(Users, url.get('users'))
if __name__ == "__main__":
# sqlalchemy
from db import db
db.__init__(app)
app.run(host='0.0.0.0', debug=True, port=5000)
flask_celery.py
from celery import Celery
def make_celery(celery_app):
celery = Celery(
celery_app.import_name,
backend=celery_app.config['CELERY_RESULT_BACKEND'],
broker=celery_app.config['CELERY_BROKER_URL']
)
celery.conf.update(celery_app.config)
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with celery_app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
user.py
from flask_restful import Resource, reqparse
from app import celery # <-- this cause the error
from util.zk_connector import zk_connect
from util.zk_error import error
class Users(Resource):
def post(self, ip, comkey):
zk = zk_connect(ip=ip, password=int(comkey))
try:
session = zk.connect()
session.disable_device()
users = session.get_users()
print(users)
session.enable_device()
session.disconnect()
return {'message': 'success'}, 200
except Exception as e:
return error(e)
#celery.task(name='user.reverse')
def reverse(string):
return string[::-1]
Error:
Traceback (most recent call last):
File ".\flask_app.py", line 6, in <module>
from resources.user import User
File "C:\Users\Gelo\Documents\Brand new clean arch pyzk\code\resources\user.py", line 2, in <module>
from flask_app import celery
File "C:\Users\Gelo\Documents\Brand new clean arch pyzk\code\flask_app.py", line 6, in <module>
from resources.user import User
ImportError: cannot import name 'User' from partially initialized module 'resources.user' (most likely due to a circular import) (C:\Users\Gelo\Documents\Brand new clean arch pyzk\code\resources\user.py)
I am fairly new to python development and have no idea about flask, I have been assigned a project that is developed using flask. After working for couple of weeks i am now able to resolve all the dependencies and project is now compiled successfully. But when I run the project using flask run and then enter the url in browser it throws "flask.cli.NoAppException". How can I run my project I have tried like this.
set FLASK_APP=init.py
set FLASK_ENV=develpment
flask run
Serving Flask app "init.py" (lazy loading)
Environment: develpment
Debug mode: on
Restarting with stat
Debugger is active!
Debugger PIN: 202-733-235
Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
here is the trackback
"FLASK_APP=myappnam:name to specify one.
Traceback (most recent call last)
File "C:\Program Files\Python38\Lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Program Files\Python38\Lib\site-packages\flask\cli.py", line 97, in find_best_app
raise NoAppException(
flask.cli.NoAppException: Failed to find Flask application or factory in module "myappnam". Use "FLASK_APP=myappnam:name to specify one.
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.
You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:
dump() shows all variables in the frame
dump(obj) dumps all that's known about the object
here is my --init--.py file
import os
import logging
import gevent
import datetime
import rollbar
from gevent.queue import Queue
from gevent.event import AsyncResult
import zmq.green as zmq
from werkzeug.contrib.fixers import ProxyFix
# Greens the postgress connector
try:
import psycogreen.gevent
psycogreen.gevent.patch_psycopg()
except ImportError:
pass
from rauth.service import OAuth2Service
from flask import Flask, Request
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager, current_user
from flask_assets import Environment
from flask_uploads import UploadSet, configure_uploads, IMAGES
from app.util import setup_logging
from app.exceptions import TimeoutError, BackendError
import app.exceptions
flask_app = None
# Have to use an actor pattern because we cannot allow more than one request to
# be pending at a time.
class Backend(gevent.Greenlet):
def __init__(self):
super(Backend, self).__init__()
self.inbox = Queue()
self.zmq_context = zmq.Context()
self.zmq_socket = None
self.init_socket()
def init_socket(self):
zmq_socket = self.zmq_socket
if zmq_socket is not None:
zmq_socket.close(0)
zmq_socket = self.zmq_context.socket(zmq.REQ)
zmq_socket.connect(flask_app.config["SERVER_ZMQ_URI"])
self.zmq_socket = zmq_socket
def process(self, request):
zmq_socket = self.zmq_socket
poller = zmq.Poller()
poller.register(zmq_socket, zmq.POLLIN)
zmq_socket.send_json({
"command": request["command"],
"arguments": request["arguments"]
})
sockets = dict(poller.poll(10 * 1000))
if zmq_socket not in sockets:
self.init_socket()
result = request["result"]
result.set_exception(TimeoutError("The request to the backend timed out."))
return
received = zmq_socket.recv_json()
result = request["result"]
if received["success"]:
result.set(received["result"])
else:
result.set_exception(BackendError(received["result"]))
def _run(self):
while True:
self.process(self.inbox.get())
def send(self, command, **kwargs):
result = AsyncResult()
self.inbox.put({
"command": command,
"arguments": kwargs,
"result": result
})
return result.get()
class RollbarRequest(Request):
#property
def rollbar_person(self):
if current_user.is_anonymous:
return {
"id": 0,
"username": "anonymous"
}
return {
"id": current_user.id,
"username": current_user.name,
"email": current_user.email_address
}
def create_app(*args, **kwargs):
global flask_app
global l
app_mode = os.environ.get("APP_MODE")
assert app_mode is not None, "APP_MODE environment variable must be set"
flask_app = Flask(__name__)
flask_app.request_class = RollbarRequest
flask_app.config.from_object("config.mode_{}".format(app_mode))
flask_app.config["APP_MODE"] = app_mode
setup_logging(flask_app.config["LOGGING_LEVEL"])
l = logging.getLogger(__name__)
l.info("starting in mode {}".format(app_mode))
if not flask_app.config["DEBUG"]:
rollbar.init(
flask_app.config["ROLLBAR_API_KEY"],
app_mode,
allow_logging_basic_config=False
)
flask_app.jinja_env.globals.update(
current_year=lambda: datetime.datetime.now().year
)
# Have to do this so that redirects work in proxy mode behind NGINX.
if not flask_app.debug:
flask_app.wsgi_app = ProxyFix(flask_app.wsgi_app)
flask_app.db = SQLAlchemy(flask_app)
flask_app.bcrypt = Bcrypt(flask_app)
flask_app.assets = Environment(flask_app)
flask_app.images = UploadSet("images", IMAGES)
configure_uploads(flask_app, flask_app.images)
flask_app.photos = UploadSet("photos", IMAGES)
configure_uploads(flask_app, flask_app.photos)
login_manager = LoginManager()
login_manager.login_view = "signin"
login_manager.login_message_category = "alert" # Need newer release of Flask-Login for this to work.
login_manager.init_app(flask_app)
flask_app.facebook = OAuth2Service(
name="facebook",
base_url="https://graph.facebook.com/v2.8/",
client_id=flask_app.config["FACEBOOK_CLIENT_ID"],
client_secret=flask_app.config["FACEBOOK_CLIENT_SECRET"]
)
from app import views
from app import models
from app import commands
flask_app.backend = Backend()
flask_app.backend.start()
app.exceptions.register(flask_app)
return flask_app
and this is my project structure
I am using pycharm and widows 10.
In your create_app function you probably do not want to use the global keyword for late initialisation of the app.
In the examples you provided the create_app function is never called, and so the app instance is never created. It is more common to use the create_app function as follows:
def create_app():
app = flask.Flask(__name__)
# do some setup
return app
app = create_app()
The app instance should also be called app and not flask_app. Of course you can call it whatever you want, but by default flask looks for app. To specify your own change FLASK_APP=__init__.py to FLASK_APP=__init__:flask_app
I'm new to flask, and REST-APIs / server side scripting in general. I get the error "ImportError: cannot import name 'flask_app'" when I try executing run_app.py
This is my dir structure.
my_project
- webapp
- __init__.py
- helpers.py
- c_data.py
- run_app.py
Contents of each file:
__init__.py
"""This is init module."""
from flask import Flask
from webapp import c_data
# Place where webapp is defined
flask_app = Flask(__name__)
c_data.py
"""This module will serve the api request."""
from app_config import client
from webapp import flask_app
from webapp import helpers
from flask import request, jsonify
# Select the database
db = client.newDB
# Select the collection
collection = db.collection
#flask_app.route("/")
def get_initial_response():
"""Welcome message for the API."""
# Message to the user
message = {
'apiVersion': 'v1.0',
'status': '200',
'message': 'Welcome to the Flask API'
}
# Making the message looks good
resp = jsonify(message)
# Returning the object
return resp
run_app.py
# -*- coding: utf-8 -*-
from webapp import flask_app
if __name__ == '__main__':
# Running webapp in debug mode
flask_app.run(debug=True)
What am I doing wrong?
It is because you import c_data in init.py, this makes recursive import
To be clearer, you import c_data and define flask_app inside __init__, but later than c_data you import flask_app which is not defined yet.
from webapp import c_data # Remove it, it makes recursive import
# Place where webapp is defined
flask_app = Flask(__name__)
Try to remove it. Or change the way to import c_data.
Possible solution, change your run_app.py
Remember to remove from webapp import c_data in __init__.py
from webapp import flask_app
from webapp import c_data # New import
if __name__ == '__main__':
# Running webapp in debug mode
flask_app.run(debug=True)