I'm trying to test the example of ToDo in Flask-Restplus site, but it keeps on getting me 404...
Basically I have 3 files:
app.py
import sys
import os
import platform
import datetime
import logging
from logging import Formatter
from logging.handlers import RotatingFileHandler
from jinja2 import Environment, PackageLoader
from flask import Flask, url_for, render_template, abort, request, Blueprint
from flask.ext.restplus import Api, Resource, fields
from werkzeug.contrib.fixers import ProxyFix
api_v1 = Blueprint('api', __name__, url_prefix='/api/1')
ns = api.namespace('todos', description='TODO operations')
TODOS = {
'todo1': {'task': 'build an API'},
'todo2': {'task': '?????'},
'todo3': {'task': 'profit!'},
}
todo = api.model('Todo', {
'task': fields.String(required=True, description='The task details')
})
listed_todo = api.model('ListedTodo', {
'id': fields.String(required=True, description='The todo ID'),
'todo': fields.Nested(todo, description='The Todo')
})
def abort_if_todo_doesnt_exist(todo_id):
if todo_id not in TODOS:
api.abort(404, "Todo {} doesn't exist".format(todo_id))
parser = api.parser()
parser.add_argument('task', type=str, required=True, help='The task details', location='form')
#ns.route('/<string:todo_id>')
#api.doc(responses={404: 'Todo not found'}, params={'todo_id': 'The Todo ID'})
class Todo(Resource):
'''Show a single todo item and lets you delete them'''
#api.doc(description='todo_id should be in {0}'.format(', '.join(TODOS.keys())))
#api.marshal_with(todo)
def get(self, todo_id):
'''Fetch a given resource'''
abort_if_todo_doesnt_exist(todo_id)
return TODOS[todo_id]
#api.doc(responses={204: 'Todo deleted'})
def delete(self, todo_id):
'''Delete a given resource'''
abort_if_todo_doesnt_exist(todo_id)
del TODOS[todo_id]
return '', 204
#api.doc(parser=parser)
#api.marshal_with(todo)
def put(self, todo_id):
'''Update a given resource'''
args = parser.parse_args()
task = {'task': args['task']}
TODOS[todo_id] = task
return task
#ns.route('/')
class TodoList(Resource):
'''Shows a list of all todos, and lets you POST to add new tasks'''
#api.marshal_list_with(listed_todo)
def get(self):
'''List all todos'''
return [{'id': id, 'todo': todo} for id, todo in TODOS.items()]
#api.doc(parser=parser)
#api.marshal_with(todo, code=201)
def post(self):
'''Create a todo'''
args = parser.parse_args()
todo_id = 'todo%d' % (len(TODOS) + 1)
TODOS[todo_id] = {'task': args['task']}
return TODOS[todo_id], 201
app = Flask(__name__)
app.secret_key = "secretkey"
app.config.from_pyfile('settings.py')
if os.path.exists(os.path.join(app.root_path, 'local_settings.py')):
app.config.from_pyfile('local_settings.py')
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgres://%s#%s/%s' % (
app.config['DB_USER'], app.config['DB_HOST'], app.config['DB_NAME'])
main.py
import sys
from flask import Blueprint
from portal.app import app
from portal import libs
if __name__ == '__main__':
if len(sys.argv) == 2:
port = int(sys.argv[1])
else:
port = 5000
host = app.config.get('HOST', '127.0.0.1')
from portal.app import api_v1
app.register_blueprint(api_v1)
import os
app.root_path = os.getcwd()
print "Running in", app.root_path, " with DEBUG=", app.config.get('DEBUG', False)
app.run(host,
port,
app.config.get('DEBUG', False),
use_reloader=True
)
tests.py
class ApiTests(helpers.ViewBase):
############################
#### setup and teardown ####
############################
def setUp(self):
super(ApiTests, self).setUp()
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
app.config['DEBUG'] = False
self.assertEquals(app.debug, False)
# executed after to each test
def tearDown(self):
pass
###############
#### tests ####
###############
def test_can_obtain_todos(self):
response = self.client.get('/api/1/todos')
self.assertEqual(response.status_code, 200)
If I run the app I can access http://localhost:5000/api/1/todos without problems, but if I run the tests, I keep to getting 404 routing exception
Traceback (most recent call last):
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1617, in dispatch_request
self.raise_routing_exception(req)
File "/home/internetmosquito/python_envs/portal/local/lib/python2.7/site-packages/flask/app.py", line 1600, in raise_routing_exception
raise request.routing_exception
NotFound: 404: Not Found
> /home/internetmosquito/git/wizbots/portal/src/portal/test/test_api.py(47)test_can_obtain_todos()
Any idea what I'm missing here? thanks!
Just for the record, test was failing because I wasn't properly initializing the blueprint again in the test file...this is done in main.py to avoid circular dependencies issues I was having.
So simply re-creating the blueprint and assigning it to app in setUp in the test file does the trick, but this is not efficient and should be avoided, guess I should check why the circular dependencies is happening and do everythng in the app.py file instead...
Related
I am testing/attempting to learn flask, and flast_restful. This issue I get is:
code 400, message Bad request syntax ('name=testitem')
main.py:
from flask import Flask,request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
product_put_args = reqparse.RequestParser()
product_put_args.add_argument("name", type = str, help = "Name of the product")
product_put_args.add_argument("quantity", type = int, help = "Quantity of the item")
products = {}
class Product(Resource):
def get(self, barcode):
return products[barcode]
def put(self, barcode):
args = product_put_args.parse_args()
return {barcode: args}
api.add_resource(Product, "/product/<int:barcode>")
if(__name__) == "__main__":
app.run(debug = True)
and my
test.py
import requests
base = "http://127.0.0.1:5000/"
response = requests.put(base + "product/1", {"name": "testitem"})
print(response.json())
I have attempted to reform mat and change around both files to figure out what is sending the issue, I feel like it is something simple, but if you can help me, I bet this will help me and many others that are trying to start creating a rest API.
You need to add the location information to the RequestParser by default it tries to parse values from flask.Request.values, and flask.Request.json, but in your case, the values need to be parsed from a flask.request.form. Below code fixes your error
from flask import Flask,request
from flask_restful import Api, Resource, reqparse
app = Flask(__name__)
api = Api(app)
product_put_args = reqparse.RequestParser()
product_put_args.add_argument("name", type = str, help = "Name of the product", location='form')
product_put_args.add_argument("quantity", type = int, help = "Quantity of the item", location='form')
products = {}
class Product(Resource):
def get(self, barcode):
return products[barcode]
def put(self, barcode):
args = product_put_args.parse_args()
products[barcode] = args['name']
return {barcode: args}
api.add_resource(Product, "/product/<int:barcode>")
if(__name__) == "__main__":
app.run(debug = True)
I am doing a few tests about my website.
My app was developped using flask,
I want to add cach-control "max-age=3600" in my function below :
from flask import Flask, jsonify, abort
from waitress import serve
import pandas as pd
from time import time as t
from load_data.connexion_to_blob import connexion_to_blob
from load_data.load_recos import load_recos
# CONFIG FILE
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# CHARGE DATA FROM BLOB
mode = 'blob'
blob_service_client = connexion_to_blob("AZURE_STORAGE_CONNECTION_STRING")
load_recos(blob_service_client, langue='fr', mode='blob')
# LOAD DATA IN APP
recos_fr_file = config['PATH']['recos_fr_file']
recos_fr = pd.read_pickle(recos_fr_file)
recos_dict = {'fr': recos_fr}
app = Flask(__name__)
#app.route('/<langue>/<program_id>/<top>')
def get_reco(langue, program_id, top=10):
t_all = t()
top = int(top)
if program_id not in list(recos_dict[langue].keys()):
abort(404, description="programId not found")
else:
recos_list = recos_dict[langue][program_id][:top]
json_output = {
"data": [
{"programId": programId}
for programId in recos_list
]
}
print("temps exec total: ", (t() - t_all))
print('---------------------------------')
return jsonify(json_output)
if __name__ == '__main__':
serve(app, host='X.X.X.X', port=XX, threads=8)
I already check some documentation,
My question is at what level should this be done?
Thank you.
We can add cach control using :
#app.after_request
def apply_caching(response):
response.headers['Cache-Control'] = 'public, max-age=3600,stale-while-revalidate=600, stale-if-error=259200'
return response
I am trying to make a website that allows a user to create their own "to-watch" list and also can randomly select a title from the created list, showing the movie's plot, genre, and IMDb rating using an API. I've encountered a "NoneType' object is not subscriptable" error message when trying to run this function and am not sure how to overcome it. Here are the relevant parts of my code:
application.py
import os
from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
from flask_session import Session
from tempfile import mkdtemp
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
from helpers import apology, login_required, imdb
app = Flask(__name__)
app.config["TEMPLATES_AUTO_RELOAD"] = True
#app.after_request
def after_request(response):
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
app.config["SESSION_FILE_DIR"] = mkdtemp()
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
db = SQL("sqlite:///project.db")
#app.route("/select", methods=["GET", "POST"])
#login_required
def select():
if request.method == "POST":
"""Randomly pick a movie to watch"""
therearemovies = db.execute("SELECT uniqueid FROM movies WHERE id=:id", id=session["user_id"])
if therearemovies:
chosen = db.execute("SELECT * FROM movies WHERE id=:id ORDER BY RANDOM() LIMIT 1", id=session["user_id"])
for uniqueindex in chosen:
suggestion = uniqueindex["title"]
**info = imdb(suggestion)
plot = info["plot"]
genre = info["genre"]
rating = info["rating"]**
return render_template("select.html", suggestion=suggestion, plot=plot, genre=genre, rating=rating)
else:
return apology("You don't have any movies in your list")
else:
return render_template("/")
helper.py:
import os
import requests
import urllib.parse
def imdb(title):
try:
response=requests.get(f"http://www.omdbapi.com/?t={urllib.parse.quote_plus(title)}&apikey=12345678")
response.raise_for_status()
except requests.RequestException:
return None
try:
data = response.json()
return
{
"plot": data["plot"],
"genre": data["genre"],
"rating": data["imdbRating"]
}
except (KeyError, TypeError, ValueError):
return None
Error Message:
File "/home/ubuntu/finalproject/helpers.py", line 32, in decorated_function
return f(*args, **kwargs)
File "/home/ubuntu/finalproject/application.py", line 126, in select
plot = info["plot"]
TypeError: 'NoneType' object is not subscriptable
This is my app.py
import logging.config
import os
from flask import Flask, Blueprint, url_for
from flask_migrate import Migrate
from flask_restplus import Api
from authentek import settings
from authentek.api.blog.endpoints.posts import ns as blog_posts_namespace
from authentek.api.blog.endpoints.categories import ns as blog_categories_namespace
from authentek.api.auth.endpoints.users import ns as users_namespace
from authentek.api.restplus import api
from authentek.database import db
app = Flask(__name__)
logging_conf_path = os.path.normpath(os.path.join(os.path.dirname(__file__), '../logging.conf'))
logging.config.fileConfig(logging_conf_path)
log = logging.getLogger(__name__)
def has_no_empty_params(rule):
defaults = rule.defaults if rule.defaults is not None else ()
arguments = rule.arguments if rule.arguments is not None else ()
return len(defaults) >= len(arguments)
#app.route("/sitemap")
def site_map():
links = []
for rule in app.url_map.iter_rules():
# Filter out rules we can't navigate to in a browser
# and rules that require parameters
if "GET" in rule.methods and has_no_empty_params(rule):
url = url_for(rule.endpoint, **(rule.defaults or {}))
links.append((url, rule.endpoint))
# links is now a list of url, endpoint tuples
def configure_app(flask_app):
flask_app.config['SERVER_NAME'] = settings.FLASK_SERVER_NAME
flask_app.config['SQLALCHEMY_DATABASE_URI'] = settings.SQLALCHEMY_DATABASE_URI
flask_app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = settings.SQLALCHEMY_TRACK_MODIFICATIONS
flask_app.config['SWAGGER_UI_DOC_EXPANSION'] = settings.RESTPLUS_SWAGGER_UI_DOC_EXPANSION
flask_app.config['RESTPLUS_VALIDATE'] = settings.RESTPLUS_VALIDATE
flask_app.config['RESTPLUS_MASK_SWAGGER'] = settings.RESTPLUS_MASK_SWAGGER
flask_app.config['ERROR_404_HELP'] = settings.RESTPLUS_ERROR_404_HELP
def initialize_app(flask_app):
configure_app(flask_app)
blueprint = Blueprint('api', __name__, url_prefix='/api')
# api.init_app(blueprint)
migrate = Migrate(flask_app, db)
api.add_namespace(blog_posts_namespace)
api.add_namespace(blog_categories_namespace)
api.add_namespace(users_namespace)
if blueprint.name not in flask_app.blueprints.keys():
flask_app.register_blueprint(blueprint)
else:
flask_app.blueprints[blueprint.name] = blueprint
print(flask_app.blueprints)
db.init_app(flask_app)
api.init_app(flask_app)
def main():
from authentek.database.models import Post, Category, User, BlacklistToken # noqa
app.config.from_object(settings)
initialize_app(app)
log.info('>>>>> Starting development server at http://{}/api/ <<<<<'.format(app.config['SERVER_NAME']))
app.run(host='0.0.0.0', debug=settings.FLASK_DEBUG)
if __name__ == "__main__":
main()
forget about all the routes, at least /sitemap should work!
I am new to python and flask, trying to import a function from route_user.py file which is present in folder named Users_service into a route_jd.py file which is present in folder named JD_service and both the folder Users_service and JD_service is present inside a folder named blue.
route_users.py file
from flask import jsonify,request,Blueprint,make_response
from flask_pymongo import PyMongo
from blue import app
from werkzeug.security import generate_password_hash,check_password_hash
import uuid
import jwt
import datetime
from functools import wraps
app.config['SECRET_KEY'] = 'itshouldbehidden'
app.config['MONGO_URI'] = "mongodb://localhost:27017/mydata"
mongo = PyMongo(app)
mod = Blueprint('Users_Service',__name__)
def token_required(f):
#wraps(f)
def decorated(*args,**kwargs):
token = None
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
if not token:
return jsonify({'message':'token is missing!'}),401
try:
data = jwt.decode(token, app.config['SECRET_KEY'])
print(data)
jd = mongo.db.hashed_User
current_user = jd.find_one({'public_id':data['public_id']})
print(current_user)
except:
return jsonify({'message':'Token is invalid'}),401
return f(current_user,*args,**kwargs)
return decorated
#mod.route('/add',methods=['POST'])
#token_required
def create_user(current_user):
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.hashed_User
data = request.get_json()
try:
hashed_password = generate_password_hash(data['password'],method='sha256')
jd.insert({"public_id":str(uuid.uuid4()),"name":data['name'],"password":hashed_password,"admin":False})
output = 'new user created!'
except:
output = 'please fill all the fields and try again'
return jsonify({'message':output})
#mod.route('/all',methods=['GET'])
#token_required
def get_all_users(current_user):
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.hashed_User
output = []
for q in jd.find():
output1={'User Name': q['name'],'Password':q['password'],'Public ID':q['public_id'],'Admin':q['admin']}
output.append(output1)
return jsonify({'Users':output})
#mod.route('/<public_id>',methods=['GET'])
#token_required
def get_one_user(current_user,public_id):
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.hashed_User
user = jd.find_one({'public_id':public_id})
if not user:
return jsonify({'message':'No such User exists'})
user_data={'User Name': user['name'],'Password':user['password'],'Public ID':user['public_id'],'Admin':user['admin']}
return jsonify({'Users':user_data})
#mod.route('/admin_promote/<public_id>',methods=['PUT'])
#token_required
def Promote_to_admin(current_user,public_id):
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.hashed_User
user = jd.find_one({'public_id':public_id})
if not user:
return jsonify({'message':'No such User exists'})
whereto = { "public_id":public_id}
newvalues={"$set":{'admin':True}}
jd.update_one(whereto,newvalues)
return jsonify({'message':'promoted to admin successfully'})
#mod.route('/delete/<public_id>',methods=['DELETE'])
#token_required
def delete_user(current_user,public_id):
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.hashed_User
user = jd.find_one({'public_id':public_id})
if not user:
return jsonify({'message':'No such User exists'})
jd = mongo.db.hashed_User
jd.delete_one({'public_id':public_id})
return jsonify({'message':'Deleted successfully'})
#mod.route('/auth/login',methods=['GET'])
def login():
auth=request.authorization
print(auth)
if not auth or not auth.username or not auth.password:
return make_response('Could not very',401,{'WWW-Authenticate':'Basic realm="Login required!"'})
jd = mongo.db.hashed_User
user = jd.find_one({'name':auth.username})
if not user:
return make_response('Could not very',401,{'WWW-Authenticate':'Basic realm="Login required!"'})
if check_password_hash(user['password'],auth.password):
token = jwt.encode({'public_id' : user['public_id'],'exp':datetime.datetime.utcnow() + datetime.timedelta(minutes=30)},app.config['SECRET_KEY'])
return jsonify({'token' : token.decode('UTF-8')})
return make_response('Could not very',401,{'WWW-Authenticate':'Basic realm="Login required!"'})
route_jd.py file
from flask import jsonify,request,Blueprint
from flask_pymongo import PyMongo
from blue import app
from blue.Users_Service import token_required # getting an error here
app.config['MONGO_URI'] = "mongodb://localhost:27017/mydata"
mongo = PyMongo(app)
mod = Blueprint('JD_Service',__name__)
#mod.route('/',methods=['GET'])
#token_required
def get_all_jds():
if not current_user['admin']:
return jsonify({'message':'cannot perform that function'})
jd = mongo.db.User11
output = []
.
.
.
.some more codes below
the error i m getting is
Traceback (most recent call last):
File "run.py", line 1, in <module>
from blue import app
File "D:\flask_resource\blue\__init__.py", line 5, in <module>
from blue.JD_Service.route_jd import mod
File "D:\flask_resource\blue\JD_Service\route_jd.py", line 4, in <module>
from blue.Users_Service import token_required
ImportError: cannot import name 'token_required'
as i m new to python and flask please help me out how to get rid of this error ?and what m i doing wrong?
Thanks in advance!
You forgot to put file name while importing in route_jd.py file:
from blue.Users_Service.route_users import token_required
Two ways:
Define Users_Service as a module, that is create a file __init__.py in folder Users_Service
Within __init__.py create import import * from blue.Users_Service.route_users
In route_jd.py: from blue.Users_Service import token_required
That is you are trying to import from module blue.Users_Service which in your case is not a module, but just a folder
Other way is to import directly:
from blue.Users_Service.route_users import token_required