how to handle http errors in flask-classful? - python

I am using flask_classful, no doubt its an amazing extension. now i want to handle http errors like 404, 500 etc. i don't know how to do that in flask-classful. Please Help me !
from flask import Flask, render_template
from flask_classful import FlaskView, route
app = Flask(__name__)
friends = ({'1st' : 'honey', '2nd' : 'ayush'})
class HomeView(FlaskView):
route_base = '/'
def home(self):
return render_template('global.html', title='Flask Claasful')
#route('/new/')
def new_func(self):
return render_template('global.html', title='Flask Classy')
#route('/friends/')
def friends(self):
return friends
HomeView.register(app)
if __name__ == '__main__':
app.run()

Related

Error when running flask app - function not defined when I make a call to the python script

Im trying to get what is essentially a spell checking tool to work. When I run locally the html appears fine in browser but when I enter data to be passed into the python script I get error: spell() not defined, even though it is and the python part works fine. I'm new to Flask apps hopefully someone can help thx
from flask import Flask, render_template, request
import string
import json
app = Flask(__name__)
#app.route("/")
#app.route("/home")
def home():
return render_template("index.html")
#app.route("/result", methods=['POST', 'GET'])
def result():
inp = request.form.to_dict()
text = inp['text']
s = spell(text)
return render_template("index.html", text=text, suggs=s)
if __name__ == '__main__':
app.run(debug=True, port=5001)
def spell(s):
copy = s
with open('english3.txt') as fh:
l = []
for line in fh:
line = line.rstrip()
l.append(line) ```
... below is just the rest of the python script
[error i get when running: html appears fine in browser but when I enter data to be passed into the python script i get this error.][1]
[1]: https://i.stack.imgur.com/lCB3y.png
Try defining the spell() function at the beginning of your script before calling it:
from flask import Flask, render_template, request
import string
import json
def spell(s):
copy = s
with open('english3.txt') as fh:
l = []
for line in fh:
line = line.rstrip()
l.append(line)
app = Flask(__name__)
#app.route("/")
#app.route("/home")
def home():
return render_template("index.html")
#app.route("/result", methods=['POST', 'GET'])
def result():
inp = request.form.to_dict()
text = inp['text']
s = spell(text)
return render_template("index.html", text=text, suggs=s)
if __name__ == '__main__':
app.run(debug=True, port=5001)

How to use Flask connexion with redis?

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 to do unit test for functions inside of Resource class in flask-restful?

I am quite new to unit testing and relatively new to RESTful API development as well. I am wondering how to do unit test for functions inside Resource class in flask restful? I can do unit test for the endpoint's response but I don't know how to do testing for the individual functions inside the endpoint's controller class.
Below is my application code. It has 3 files including test:
api.py
controller_foo.py
test_controller_foo.py
# api.py
from flask import Flask
from flask_restful import Api
from .controller_foo import ControllerFoo
def create_app(config=None):
app = Flask(__name__)
app.config['ENV'] ='development'
return app
application = app = create_app()
api = Api(app)
api.add_resource(ControllerFoo, '/ctrl')
if __name__ == "__main__":
app.run(debug=True)
# controller_foo.py
from flask_restful import Resource
from flask import request
class ControllerFoo(Resource):
"""
basically flask-restful's Resource method is a wrapper for flask's MethodView
"""
def post(self):
request_data = self.handle_request()
response = self.process_request(request_data)
return response
def handle_request(self):
json = request.get_json()
return json
def process_request(self, data):
# do some stuffs here
return {'foo': 'bar'}
I am using unittest
# test_controller_foo.py
import unittest
from api import app
from .controller_foo import ControllerFoo
# initiating class to try testing but I don't know how to start
ctrl = ControllerFoo()
class ControllerFooTestCase(unittest.TestCase):
def setUp(self):
self.app = app
self.app.config['TESTING'] = True
self.client = app.test_client()
self.payload = {'its': 'empty'}
def tearDown(self):
pass
def test_get_response(self):
response = self.client.post('/ctrl', json=self.payload)
expected_resp = {
'foo': 'bar'
}
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.get_json(), expected_resp)
if __name__ == "__main__":
unittest.main()
I want to know how to properly do unit test for handle_request and process_request function
EDIT: Fixing out my buggy code. Thanks Laurent LAPORTE for the highlights.
There are several bugs in your code, so this is not easy to explain.
First of all, the recommended way to do testing with Flask (and Flask-Restful) is to use PyTest instead of unittest, because it is easier to setup and use.
Take a look at the documentation: Testing Flask Applications.
But, you can start with unittest…
note: you can have a confusion with your app module and the app instance in that module. So, to avoid it, I imported the module. Another good practice is to name your test module against the tested module: "app.py" => "test_app.py". You can also have a confusion with the controller module and the controller instance. The best practice is to use a more precise name, like "controller_foo" or something else…
Here is a working unit test:
# test_app.py
import unittest
import app
class ControllerTestCase(unittest.TestCase):
def setUp(self):
self.app = app.app
self.app.config['TESTING'] = True
self.client = self.app.test_client()
self.payload = {'its': 'empty'}
def test_get_response(self):
response = self.client.post('/ctrl', json=self.payload)
expected_resp = {'foo': 'bar'}
self.assertEqual(response.status_code, 200)
self.assertDictEqual(response.get_json(), expected_resp)
if __name__ == "__main__":
unittest.main()
As you can see, I also fixed the posted URL, in your application, the URL is "/ctrl", not "controller".
At this point, the test can run, but you have another error:
Ran 1 test in 0.006s
FAILED (errors=1)
Error
Traceback (most recent call last):
...
TypeError: process_request() takes 1 positional argument but 2 were given
If you take a look at your process_request() method, you can see that you missed the self parameter. Change it like this.
def process_request(self, data):
# do some stuffs here
return {'foo': 'bar'}
Your test should pass.
But, that not the right way to implement Flask-Restful controolers. Read the doc and use get and post methods…

NameError: name 'ask' is not defined

problem with flask ask
#ask.launch issue
am having problem running my python flask script. I am using python 2.7, the error says:
File "C:\Users\user1\AppData\Local\Continuum\anaconda2\Lib\site-packages\hello_lumion.py", line 13, in #ask.launch NameError: name 'ask' is not defined
import logging
import os
from flask import request
from flask import Flask
from flask_ask import Ask, statement, request, context, session, question, version
import requests
#ask.launch
def welcome():
return statement ('Welcome to Foo')
app = Flask(__name__)
ask= Ask(app,"/")
logging.getLogger("flask_ask").setLevel(logging.DEBUG)
#ask.intent("Hello")
def hello():
msg= "hello from lumion"
return statement (msg)
if __name__ == '__main__':
port = 9000
app.run(host='0.0.0.0', port=port)
app.run(debug=True)
any advice on how to overcome this issue?
You are calling ask before it is defined. In your code you have
#ask.launch # ask has not been made
def welcome():
return statement ('Welcome to Foo')
app = Flask(__name__)
ask= Ask(app,"/") # ask gets made here!
You will need to reorder it so when you call ask, it has been defined. Something like:
app = Flask(__name__)
ask= Ask(app,"/") # define it first
#ask.launch # now use it
def welcome():
return statement ('Welcome to Foo')

How can I make command line arguments visible to Flask routes?

I am using Flask to build a tool to view data locally in a browser. I want to pass the directory containing the data as a command line argument, and then pass it to the appropriate routing function to do the rendering.
This does what I want, but with global variables:
dataDir = None
def initializeData(pathname):
global dataDir
dataDir = pathname
#app.route('/')
def home():
# Use dataDir as desired
if __name__ == '__main__':
initializeData(sys.argv[1])
app = Flask(__name__)
app.run()
Is there a better way to communicate between the command line and my routes?
Your flask app has a config property. Also, this code will fail with a NameError. You want something like this:
import sys
from flask import Flask
app = Flask(__name__)
#app.route('/')
def home():
return 'You wanted {!r} directory'.format(app.config.get('some_setting'))
if __name__ == '__main__':
app.config['some_setting'] = sys.argv[1]
app.run()
Consider using app.config.from_json('config.json') so that you can configure your env parameters in a json file.

Categories