Flask App accessing routes defined in a class - python

I am new to python , I have a class and it has two routes defined on it. How do I bind those routes to the main flask server running.
Here is my restinput.py
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import logging
from rasa_core.channels import HttpInputChannel
from rasa_core import utils
from rasa_core.agent import Agent
from rasa_core.interpreter import RasaNLUInterpreter
from rasa_core.channels.channel import UserMessage
from rasa_core.channels.direct import CollectingOutputChannel
from flask import Blueprint, request, jsonify
logger = logging.getLogger(__name__)
class RestInput(InputChannel):
#classmethod
def name(cls):
return "rest"
#staticmethod
def on_message_wrapper(on_new_message, text, queue, sender_id):
collector = QueueOutputChannel(queue)
message = UserMessage(text, collector, sender_id,
input_channel=RestInput.name())
on_new_message(message)
queue.put("DONE")
def _extract_sender(self, req):
return req.json.get("sender", None)
def _extract_message(self, req):
return req.json.get("message", None)
def stream_response(self, on_new_message, text, sender_id):
from multiprocessing import Queue
q = Queue()
t = Thread(target=self.on_message_wrapper,
args=(on_new_message, text, q, sender_id))
t.start()
while True:
response = q.get()
if response == "DONE":
break
else:
yield json.dumps(response) + "\n"
def blueprint(self, on_new_message):
custom_webhook = Blueprint(
'custom_webhook_{}'.format(type(self).__name__),
inspect.getmodule(self).__name__)
#custom_webhook.route("/", methods=['GET'])
def health():
return jsonify({"status": "ok"})
#custom_webhook.route("/webhook", methods=['POST'])
def receive():
sender_id = self._extract_sender(request)
text = self._extract_message(request)
should_use_stream = utils.bool_arg("stream", default=False)
if should_use_stream:
return Response(
self.stream_response(on_new_message, text, sender_id),
content_type='text/event-stream')
else:
collector = CollectingOutputChannel()
on_new_message(UserMessage(text, collector, sender_id,
input_channel=self.name()))
return jsonify(collector.messages)
return custom_webhook
def run(serve_forever=True):
interpreter = RasaNLUInterpreter("models/nlu/default/current")
action_endpoint = EndpointConfig(url="http://localhost:5055/webhook")
agent = Agent.load("models/dialogue", interpreter=interpreter,action_endpoint=action_endpoint)
input_channel = RestInput()
if serve_forever:
agent.handle_channels([InputChannel(5004, "/chat", input_channel)])
return agent
This is my app.py
from flask import Flask
from flask_cors import CORS
from restinput import RestInput
app = Flask(__name__)
CORS(app)
#app.route("/")
def index():
return "Hello"
#app.route("/parse",methods=['POST'])
def chat():
#some code to access the class on this route
if __name__ == "__main__":
app.run(host='0.0.0.0')
What should I add in the "/parse" route , to be able to access the routes from the RestInput class.
I tried creating the agent in the /parse route and then accessing the other routes like the /parse/webhook , but it is not working. I have gone through the flask blueprint and view but I am unable to figure it out.

Routes in RestInput are attached to a Blueprint. To attach those routes to your main app you should register a blueprint:
# app.py
some_function = ... # whatever you want
app.register_blueprint(RestInput().blueprint(some_function))

Related

Testing flask pages with flask login

I'm struggling on how to test any views of my Flask app that are behind #login_required
this is my configtst.py
import os
from unittest import mock
import pytest
from app import create_app, db
#pytest.fixture
def test_app():
"""A test app instance with test env vars"""
with mock.patch.dict(os.environ, {"APP_SECRET": "XJASGHA1", "DATABASE_URL" : "sqlite:///testdb.sqlite"}):
app = create_app()
app.config['TESTING'] = True
app.config['LOGIN_DISABLED'] = True
return app
#pytest.fixture
def client(test_app):
"""A test client for the app."""
return test_app.test_client()
#pytest.fixture
def runner(app):
return app.test_cli_runner()
this is my test_panel.py
from app import *
from app.models import *
from cofigtst import *
def test_login(client):
with client:
res = client.post("/login", data={"email": "joe#doe.com", "password" : "JoeDoe123"}, follow_redirects=True)
assert "you are logged in" in res.data
If logged in, this assertion should pass. I checked previous SO questions, but nothing fixes my case.
I wanted to see what is inside of testdb.sqlite but I don't see where it is created... Any ideas?

APScheduler RuntimeError: No application found

I have a problem. I have IP addresses and with APScheduler I try to ping them every 10 seconds and update my database. For APScheduler I understand that I need to use with app.app_context() but the problem is that I don't know where to place it and wherever I have tried to place it, it raise: RuntimeError: No application found and fails to update the database
init.py:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from os import path
db = SQLAlchemy()
DB_NAME = "database.db"
def create_app():
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hjshjhdjah kjshkjdhjs'
app.config['SQLALCHEMY_DATABASE_URI'] = f'sqlite:///{DB_NAME}'
db.init_app(app)
from .views import views
from .auth import auth
app.register_blueprint(views, url_prefix='/')
app.register_blueprint(auth, url_prefix='/')
from .models import Servers
create_database(app)
return app
def create_database(app):
if not path.exists('websiteflaskupdatedd/' + DB_NAME):
db.create_all(app=app)
print('Created Database!')
auth.py:
from flask import Blueprint, render_template, request, flash, redirect, url_for, escape, session
from .models import Servers, ping
from . import db, create_app
from apscheduler.schedulers.background import BackgroundScheduler
#auth.route('/servers', methods = ['POST', 'GET'])
def servers():
if request.method == 'POST':
server_ip = request.form.get("server_ip")
new_server = Servers(server_ip = server_ip)
try:
db.session.add(new_server)
db.session.commit()
return redirect("/servers")
except:
return "There was an error adding your server"
else:
if not Servers.query.get(1) == None:
servers = Servers.query.order_by(Servers.date_created)
return render_template('servers.html', servers=servers)
def update_up_status():
with create_app().app_context():
server_status_column = Servers.query.filter(Servers.server_status.in_(["0","1"]))
for server in server_status_column:
server.server_status = ping(server.server_ip)
db.session.commit()
scheduler = BackgroundScheduler()
if not scheduler.running:
scheduler.add_job(func=update_up_status, trigger="interval", seconds=10)
scheduler.start()
models.py:
from . import db
from datetime import datetime
import platform
import subprocess
def ping(host):
cmd = ['ping', '-w', "1", "-n", '1', host]
return subprocess.call(cmd) == 0
class Servers(db.Model):
id = db.Column(db.Integer, primary_key=True)
server_ip = db.Column(db.String(12), nullable=False, unique=True)
server_status = db.Column(db.String(12), nullable=False)
date_created = db.Column(db.DateTime, default= datetime.now)
Looks like you don't have your application running.
I use this setup regularly (flask + apscheduler) and have a main.py file with the following (including the necessary module imports from your other files):
if __name__ == "__main__":
scheduler = BackgroundScheduler()
scheduler.add_job(func=update_up_status, trigger="interval", seconds=10)
scheduler.start()
app.run(host="0.0.0.0", debug=True)
The background scheduler works within the background of another application and will not be blocked by the main thread which in this case is the flask application. As opposed to the blocking scheduler which will block the main thread and cannot be run inside of a another application.
Just like this.
def insertArticles(articles):
from app import db
from app.models.articles import Article
from app import scheduler
# 解决 flask apscheduler RuntimeError: No application found
with scheduler.app.app_context():
for article in articles:
# 字典 解包,直接插入字典
new_article = Article(**article)
db.session.add(new_article)
db.session.flush()
db.session.commit()
with scheduler.app.app_context() is the important line.

generating flask route from class method

i am trying to generate Flask route using a basic DI i.e mapping methods as route handlers, i am a total beginner at Flask so mind my basic skills
class myClass():
def __init__(self):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
def my_method(self, event):
retun "hello"
and then in my handler file
from flask import Flask
from flask_restful import Api, Resource
from src.app.services.myClassimport myClass
app = Flask(__name__)
app.register_blueprint(myClass.blueprint)
if __name__ == "main":
app.run()
Quite simple ehh???? but not working... i am getting following message
Not Found The requested URL was not found on the server. If you
entered the URL manually please check your spelling and try again.
typically you add routes to the Flask app with decorators like so:
app = Flask(__name__)
#app.route('/some-endpoint')
def some_endpoint_handler():
# do something
pass
Or you can add without a decorator like so:
def some_endpoint_handler():
# do something
pass
app = Flask(__name__)
app.route('/some-endpoint', methods=['GET'])(some_endpoint_handler)
So in your scenario, you can pass the app.route call to your myClass object and set the route like this:
class myClass():
def __init__(self, router):
self.dbConnObj = DbToolsMySql('someconnection', 'slave')
self.dbConnObj.connect()
self.blueprint = Blueprint('myClass', __name__)
#self.blueprint.add_url_rule('/my_method', view_func=self.my_method)
router('/my_method', ['GET'])(self.my_method)
def my_method(self, event):
retun "hello"
myObj = myClass( app.route )
or, invert the dependency:
app = Flask(__name__)
#app.route(myClass.blueprint.some_endpoint_string)
def some_endpoint_handler():
myClass.blueprint.call_some_endpoint_handler()
pass
if __name__ == "main":
app.run()

Working outside of application context; FlaskClient object has no attribute 'app_context'

We are getting FlaskClient object has no attribute 'app_context' with this test:
app.py:
import logging
from logging.handlers import RotatingFileHandler
from blueprints import default, otherstuff
from global_vars import app, db
def generate_app():
app.config.from_object('config.flask_config')
db.init_app(app)
# registering blueprints
app.register_blueprint(default.default)
app.before_request(oauth_package.authenticate_all_requests)
return app
if __name__ == '__main__':
flask_app = generate_app()
flask_app.run(port=5002, debug=True)
testfile.py:
import unittest
import mock
from starter_file import generate_app
import flask
import blueprints
class TestBase(unittest.TestCase):
def setUp(self):
# creates a test client
app = generate_app()
app.testing = True
self.app = app.test_client()
# propagate the exceptions to the test client
#mock.patch('blueprints.default.get_current_user_role')
def test_qppage_without_coockie(self, mocked_get_current_user_role):
mocked_get_current_user_role.return_value = 'ap'
with self.app.app_context():
result = blueprints.default.home()
print result
# assert the status code of the response
self.assertEqual(result.status_code, 302)
if __name__ == '__main__':
unittest.main()
and Runtime error: Working outside of application context with this code:
class TestBase(unittest.TestCase):
def setUp(self):
# creates a test client
app = generate_app()
app.testing = True
self.app = app.test_client()
# propagate the exceptions to the test client
#mock.patch('blueprints.default.get_current_user_role')
def test_qppage_without_coockie(self, mocked_get_current_user_role):
mocked_get_current_user_role.return_value = 'ap'
result = blueprints.default.home()
print result
# assert the status code of the response
self.assertEqual(result.status_code, 302)
Try to add this in your TestBase class:
...
from flask import current_app
...
#classmethod
def setUpClass(cls):
cls.app = generate_app()
def setUp(self):
"""Set up application for testing."""
with self.app.app_context():
self.test_app = current_app.test_client()
# Here goes the rest of your code

Error handler import works only after we adding all app_rules

Why is the code marked NOT WORKING, not working and throwing a respective error? What is the right way to do it ? import * is not the right way.
My routing.py:
import os
from flask import Flask
from views import UserView
#App Config
app= Flask(__name__)
# ********************** NOT WORKING ****************************
# from error_handlers import auth_error ==> AssertionError: View function mapping is overwriting an existing endpoint function: user_view
# from error_handlers import * ==> AssertionError: View function mapping is overwriting an existing endpoint function: user_view
# ***************************************************************
#URLs
app.add_url_rule('/users', view_func=UserView.as_view('user_view'), methods=['GET'])
# ********************** NOT WORKING ****************************
# from error_handlers import auth_error ==> ImportError: cannot import name auth_error
# ***************************************************************
# ********************** WORKING ****************************
from error_handlers import *
# ***************************************************************
if __name__ == '__main__':
app.run(debug=True, host = '0.0.0.0', port=5050)
error_handlers.py is:
from flask import render_template, jsonify
from routing import app
from myexceptions import *
#Error Handlers
#app.errorhandler(404)
def unexpected_error(error):
""" error handler for unknown error """
return render_template('error.html'), 404
#app.errorhandler(AuthenticationException)
def auth_error(error):
""" error handler user entered data exception """
return jsonify({'error': error.get_message()})
views.py is:
from flask.views import View
from flask import render_template
from myexceptions import AuthenticationException
class ParentView(View):
def get_template_name(self):
raise NotImplementedError()
def render_template(self, context):
return render_template(self.get_template_name(), **context)
def dispatch_request(self):
context = self.get_objects()
return self.render_template(context)
class UserView(ParentView):
def get_template_name(self):
raise AuthenticationException('test')
return 'users.html'
def get_objects(self):
return {}
and AuthenticationException is just a Exception subclass defined in myexceptions.
I'v also read your code in your github before,maybe the error is : you import app in some files which doesn't use app
My modifid code :
routing.py
import os
from flask import Flask
#App Config
app= Flask(__name__)
from views import UserView
app.add_url_rule('/users', view_func=UserView.as_view('user_view'), methods=['GET'])
if __name__ == '__main__':
print app.url_map
app.run(debug=True, host = '10.210.71.145', port=5050)
and your error_handle.py maybe like this:
from flask import render_template, jsonify
from myexceptions import AuthenticationException
#app.errorhandler(404)
def unexpected_error(error):
""" error handler for unknown error """
return render_template('error.html'), 404
#app.errorhandler(AuthenticationException)
def auth_error(error):
""" error handler user entered data exception """
return jsonify({'error': error.get_message()})

Categories