Flask-socketio AttributeError: 'Request' object has no attribute 'sid' - python

I am getting this error: AttributeError: 'Request' object has no attribute 'sid' when using socketio in flask. Here is the output:
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/user/tennisprogram/application.py", line 34, in create_game_post
join_room(str(gameid))
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/flask_socketio/__init__.py", line 865, in join_room
sid = sid or flask.request.sid
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/werkzeug/local.py", line 347, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'Request' object has no attribute 'sid'
Here is the code I'm using. If you need something other than the backend please let me know and I'd be happy to include it :).
Input:
from flask import Flask, redirect, request, render_template, session, url_for
from flask_socketio import SocketIO, emit, join_room, leave_room, close_room
app = Flask(__name__)
socket = SocketIO(app)
app.config["SECRET_KEY"] = 'secret-key'
games = [None, None, None, None, None, None, None, None, None, None]
class Game:
def __init__(self, player1, player2, id):
self.id = id
self.infodictionary = {"player1_name":player1, "player1_score":["0", "0", "0"], "player2_name":player2, "player2_score":["0", "0", "0"]}
#app.route("/")
def index():
return render_template("index.html")
#app.route("/create_game")
def create_game():
return render_template("create_game.html")
#app.route("/create_game/post", methods=["POST"])
def create_game_post():
if "host" in session:
return "Already hosting a game" #Handle later
for gameid, game in enumerate(games):
if game == None:
game = Game(request.form.get("player1"), request.form.get("player2"), gameid)
games[gameid] = game
session["host"] = gameid
return redirect(url_for('game', id=game.id))
return "No game slot available" #Handle later
#app.route("/game/<id>")
def game(id):
join_room(str(id))
if int(id) == session["host"]:
return render_template("score.html", host=True, game=games[int(id)])
else:
return render_template("score.html", host=False, game=games[int(id)])
#socket.on("host-update")
def update(data):
p1 = data["player1_score"]
p2 = data["player2_score"]
games[int(data["id"])].infodictionary["player1_score"] = p1
games[int(data["id"])].infodictionary["player2_score"] = p2
emit("update", {"player1_score":p1, "player2_score":p2}, room=data["id"])
#Handling join game
'''
#socket.on("joingame")
def join(data):
r = data["room"]
join_room(r)
'''
#app.route("/join_game")
def join_game():
return render_template("join_game.html")
#join_game.html will redirect user to join_game_post. The socket will activate in join_game.html
#app.route("/join_game/join", methods=["POST"])
def join_game_post():
id = request.form.get("id")
return redirect(url_for("game", id=id))
#app.route("/del")
def delete_host():
games[int(session["host"])] = None
del session["host"]

Referring to the answer here about AttributeError: 'Request' object has no attribute 'sid'
I believe that your error maybe caused by this line
*emit("update", {"player1_score":p1, "player2_score":p2}, room=data["id"])
Quoting the reason from the source above
emit() function has a default of emitting to the sender of an originating event. This default only makes sense when you call the function from an event handler. You are calling it from a route, which does not have the Socket.IO context (in particular, request.sid).
Do you know to which user(s) you want to emit an event from this
route? If you want to emit to all your connected clients, add
broadcast=True. If you know the sid of the user you want to address,
then add room=sid. You also need to specify the namespace, so add
namespace='/' or use the proper namespace name.
The error could also be as simple as, user has been disconnected before being routed/redirected.

Related

AttributeError: 'dict' object has no attribute 'get_reset_password_token'

I have been following the guide at https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-x-email-support to implement a password reset feature in my Flask app.
My error is:
Traceback (most recent call last):
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\David PC\AppData\Local\Programs\Python\Python310\lib\site-packages\flask\app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "C:\Users\David PC\Desktop\VS Code Python\Flask Site\app.py", line 691, in passwordreset
EmailSender(form.email.data, "Password reset", {"url": url_for("reset_password", token=user.get_reset_password_token(), _external=True)}, 6)
AttributeError: 'dict' object has no attribute 'get_reset_password_token'
My route view is:
#app.route('/passwordreset', methods=['GET', 'POST'])
def passwordreset():
if current_user.is_authenticated:
return redirect(url_for('profile'))
form = ResetPasswordRequestForm()
if form.validate_on_submit():
user = mycol.find_one({"email": form.email.data})
if user:
EmailSender(form.email.data, "Password reset", {"url": url_for("reset_password", token=user.get_reset_password_token(), _external=True)}, 6)
return redirect(url_for('homepage'))
flash('If an account with this email was registered please check your email.')
return render_template('reset_password_request.html', title='Reset Password', form=form)
And my User class is:
class User(UserMixin):
def __init__(self, user_json):
self.user_json = user_json
def get_id(self):
object_id = self.user_json.get('_id')
return str(object_id)
def get_reset_password_token(self, expires_in=600):
return jwt.encode(
{'reset_password': self.id, 'exp': time() + expires_in},
app.config['SECRET_KEY'], algorithm='HS256')
#staticmethod
def verify_reset_password_token(token):
try:
id = jwt.decode(token, app.config['SECRET_KEY'],
algorithms=['HS256'])['reset_password']
except:
return
return User.query.get(id)
I have a sneaking suspicion I am missing something basic but I cannot seem to figure it out. Any help would be appreciated!
As noted by #Matiss, I had to wrap my pymongo DB query in my User class.
user = User(mycol.find_one({"email": form.email.data}))
This was the fix to the attribute error.

How to properly map user defined methods to GET/POST HTTP calls in Python Flask?

I am new to Python-Flask and trying to implement APIs in it.
To do that, I have created two APIs which will receive the values and then display the values.
Code:
from flask import Flask, jsonify, request
from flask_restful import Resource, Api, reqparse
app = Flask(__name__)
api = Api(app)
vehicles = []
class VehicleData(Resource):
parser = reqparse.RequestParser()
parser.add_argument('vehicle', type=str, required=True, help='name cannot be empty')
parser.add_argument('type', type=str, required=True, help='vehicle type cannot be empty')
parser.add_argument('wheels', type=int, required=True, help='number of wheels cannot be empty')
parser.add_argument('suv', type=bool, required=False, help='SUV or not can be empty')
def get(self, name):
vehicle = list(filter(lambda x: x['name'] == name, vehicles), None)
return {'vehicle': vehicle}, 200 if vehicle else 404
def post(self, name):
# data = request.get_json()
# sport.append({'sportname': data['sport_name'], 'team_size':data['team_size'], 'popularity':data['popularity']})
if next(filter(lambda x: x['name'] == name, vehicles), None) is not None:
print("in the IF BLOCK")
return {'message': 'The vehicel {n} already exists in the database'.format(n=name)}, 404
v_data = VehicleData.parser.parse_args()
vehicle = {'name': name, 'type':v_data['type'], 'vehicle': v_data['vehicle'], 'suv': v_data['suv'], 'wheels': v_data['wheels']}
vehicles.append(vehicle)
return vehicle, 201
def getallvehicles(self):
return {'vehicles': vehicles}
api.add_resource(VehicleData, '/addvehicle/<string:name>', '/getvehicle/<string:name>', '/getallvehicles')
app.run(port=5000, debug=True)
Api Calls:
http://127.0.0.1:5000/addvehicle/polo
http://127.0.0.1:5000/getvehicle/polo
http://127.0.0.1:5000/getallvehicles
The calls to the methods POST and GET are working fine which can be seen in the image.
But when I run the third API which gives me all the entries of the list: vehicles, the code is giving an error saying it needs an argument name.
Traceback (most recent call last):
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask_restful/__init__.py", line 272, in error_router
return original_handler(e)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/_compat.py", line 38, in reraise
raise value.with_traceback(tb)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask_restful/__init__.py", line 272, in error_router
return original_handler(e)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/_compat.py", line 38, in reraise
raise value.with_traceback(tb)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask_restful/__init__.py", line 468, in wrapper
resp = resource(*args, **kwargs)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask/views.py", line 89, in view
return self.dispatch_request(*args, **kwargs)
File "/Users/bobby/PyCharmProjects/FlaskAPI/venv/lib/python3.7/site-packages/flask_restful/__init__.py", line 583, in dispatch_request
resp = meth(*args, **kwargs)
TypeError: get() missing 1 required positional argument: 'name'
I understand that the GET call is invoking get() in the code and not getallvehicles().
Is it because getallvehicles is a user defined method ? If so, could anyone let me know how to map a user defined method to GET or POST or any corresponding call. In this case, how can I map getallvehicles to GET http call ?
Approach 1:
I can add an extra class to the existing code & register in my API to return all the data from the list: vehicles
class GetAllVehicles(Resource):
def get(self):
return {'vehicles': vehicles}
api.add_resource(GetAllVehicles, '/getallvehicles')
How can I achieve the same functionality without using an extra class in the code and map GET to getallvehicles()
Not exactly what you requested, but I would use a keyword 'all' as a possible input for getting all the vehicle data in the API.
class VehicleData(Resource):
parser = reqparse.RequestParser()
parser.add_argument('vehicle', type=str, required=True, help='name cannot be empty')
parser.add_argument('type', type=str, required=True, help='vehicle type cannot be empty')
parser.add_argument('wheels', type=int, required=True, help='number of wheels cannot be empty')
parser.add_argument('suv', type=bool, required=False, help='SUV or not can be empty')
def get(self, name):
if name == 'all': # return all vehicles if 'all' keyword is passed
return {'vehicles': vehicles}
else:
vehicle = list(filter(lambda x: x['name'] == name, vehicles), None)
return {'vehicle': vehicle}, 200 if vehicle else 404
def post(self, name):
# data = request.get_json()
# sport.append({'sportname': data['sport_name'], 'team_size':data['team_size'], 'popularity':data['popularity']})
if next(filter(lambda x: x['name'] == name, vehicles), None) is not None:
print("in the IF BLOCK")
return {'message': 'The vehicle {n} already exists in the database'.format(n=name)}, 404
elif name == 'all': # prevent adding a vehicle named 'all'
return {'message': 'Invalid vehicle name'}, 404
v_data = VehicleData.parser.parse_args()
vehicle = {'name': name, 'type':v_data['type'], 'vehicle': v_data['vehicle'], 'suv': v_data['suv'], 'wheels': v_data['wheels']}
vehicles.append(vehicle)
return vehicle, 201
api.add_resource(VehicleData, '/addvehicle/<string:name>', '/getvehicle/<string:name>')
app.run(port=5000, debug=True)
The modified code above returns all vehicles if the url /getvehicle/all is entered and prevents adding a car named 'all' in the post() function.
Not sure if I've fully understand your requirements but my interpretation is that you have three end-points:
Add vehicle (loads data)
Get vehicle (gets the data of one of the vehicles based on an input)
Get all vehicles (gets data for all of the vehicles)
I would suggest storing the output in a nested dictionary as this makes it easier to manipulate.
from flask import Flask, request
global vehicles
vehicles = {}
my_app = Flask(__name__)
#my_app.route('/load_vehicle', methods=['POST'])
def load_vehicle():
"""
Example JSON:
{'compass':{'type':'car',
'vehicle':'automobile',
'suv':True,
'wheels':4}}
"""
global vehicles
json_in = request.get_json(silent=True)
if json_in != None:
vehicles.update(json_in)
#my_app.route('/get_vehicle', methods=['POST'])
def get_vehicle():
"""
Example JSON:
{'name':'compass'}
"""
global vehicles
json_in = request.get_json(silent=True)
if json_in != None:
output = vehicles[json_in['name']]
return output
#my_app.route('/get_all', methods=['GET'])
def get_all():
global vehicles
return vehicles

Can't pass variables to html through flask

I’m trying to get data from postgressql through SQLAlchemy and loop items in to a html page.
I’m doing something wrong but I can’t finger it out.
config.py
import connexion
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow
connex_app = connexion.App(__name__)
# Get the underlying Flask app instance
app = connex_app.app
# Configure the SqlAlchemy part of the app instance
app.config["SQLALCHEMY_ECHO"] = True
app.config["SQLALCHEMY_DATABASE_URI"] = "postgresql://hey:hey2#localhost/heys"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
# Create the SqlAlchemy db instance
db = SQLAlchemy(app)
# Initialize Marshmallow
ma = Marshmallow(app)
models.py
from config import db, ma
from sqlalchemy import Column, Integer, String
class types(db.Model):
__tablename__='types'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
class TypesSchema(ma.ModelSchema):
class Meta:
model = types
sqla_session = db.session
types.py
from flask import make_response, abort
from config import db
from models import types, TypesSchema
def all_types():
# Create the list of wine type from our data
types = types.query.order_by(types.id).all()
# Serialize the data for the response
types_schema = TypesSchema(many=True)
data = types_schema.dump(types).data
return data
app.py
from flask import render_template
import json
# local modules
import config
# Get the application instance
connex_app = config.connex_app
# create a URL route in our application for "/"
#connex_app.route("/")
def all_types():
return render_template("index.html", types=all_types)
if __name__ == "__main__":
connex_app.run(debug=True)
index.html
...
<tbody>
{% for type in types %}
<h1>Name: {{type.name}}</h1>
<h2>ID: {{type.id}}</h2>
{% endfor %}
</tbody>
...
The return from types.py gives
[{'id': 1, 'name': 'Red wine'}, {'id': 2, 'name': 'White wine'}, {'id': 3, 'name': 'Sparkling'}, {'id': 4, 'name': 'Rosé'}, {'id': 7, 'name': 'Sweet Wine'}, {'id': 24, 'name': 'Tawny'}, {'id': 25, 'name': 'Not Classified'}]
But when I run it, I get "TypeError: 'function' object is not iterable".
What I'm doing wrong?
Traceback update
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/2/Library/Python/3.7/lib/python/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/2/Desktop/Python/Vino_app/app.py", line 23, in all_types
return render_template("index.html", types=types.all_types())
AttributeError: module 'types' has no attribute 'all_types'
You have two things called all_types here - your handler and your utility function - which is confusing. But in fact you're not actually calling either of them. What you're doing is passing a reference to the current handler function into your template, which naturally doesn't know what to do with it.
You need to import your types module into your apps.py and then pass the result of calling the function:
import types
...
#connex_app.route("/")
def all_types():
return render_template("index.html", types=types.all_types())

Python ldap function behaves differently when called in flask

So I'm trying get auto-complete to work with python-ldap and flask.
Here's a test script ldapA.py:
import ldap
#first you must open a connection to the server
def query():
try:
l = ldap.open("server.net")
## searching doesn't require a bind in LDAP V3. If you're using LDAP v2, set the next line appropriately
## and do a bind as shown in the above example.
# you can also set this to ldap.VERSION2 if you're using a v2 directory
# you should set the next option to ldap.VERSION2 if you're using a v2 directory
l.protocol_version = ldap.VERSION3
l.set_option(ldap.OPT_REFERRALS, 0)
username="CN=user user,OU=bbbgbg,OU=bdbfd,DC=dsffd,DC=net"
passw="adsada"
l.simple_bind_s(username,passw)
except ldap.LDAPError, e:
print e
# handle error however you like
## The next lines will also need to be changed to support your search requirements and directory
baseDN = "ou=xds, ou=sd, dc=sd, dc=net"
searchScope = ldap.SCOPE_SUBTREE
## retrieve all attributes - again adjust to your needs - see documentation for more options
retrieveAttributes = ['name']
searchFilter = "name=*jace*"
try:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
result_set = []
while 1:
result_type, result_data = l.result(ldap_result_id, 0)
if (result_data == []):
break
else:
## here you don't have to append to a list
## you could do whatever you want with the individual entry
## The appending to list is just for illustration.
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
res = result_set[0]
res1 = res[0]
res2 = res1[1]
res3 = res2["name"]
print res3[0]
except ldap.LDAPError, e:
print e
query()
It works as intended when I run it. It gives me my name from the AD.
Now when I call it from flask like this:
from flask import render_template
from app import app
from flask import request
from ldapA import query
#app.route('/')
#app.route('/index')
def index():
return render_template("index.html")
#app.route('/autocomplete', methods=['GET'])
def autocomplete():
return query()
I get:
127.0.0.1 - - [19/Jul/2017 14:08:58] "GET /autocomplete HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/flask/app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/jgar/receptionsignin/app/views.py", line 13, in autocomplete
return query()
File "/home/jgar/receptionsignin/ldapA.py", line 36, in query
result_type, result_data = l.result(ldap_result_id, 0)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 703, in result
resp_type, resp_data, resp_msgid = self.result2(msgid,all,timeout)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 707, in result2
resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all,timeout)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 714, in result3
resp_ctrl_classes=resp_ctrl_classes
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 734, in result4
resp_data = self._bytesify_results(resp_data, with_ctrls=add_ctrls)
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 266, in _bytesify_results
for (dn, fields) in results
File "/home/jgar/receptionsignin/flask/lib/python2.7/site-packages/ldap/ldapobject.py", line 219, in _maybe_rebytesify_text
assert isinstance(value, text_type), "Should return text, got bytes instead (%r)" % (value,)
AssertionError: Should return text, got bytes instead ('CN=sdsddsc,OU=sds,OU=sds,DC=sdds,DC=net')
I know that this line causes the trouble:
ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
But I'm stumped as to why it happens when called in flask and not when run with python ldapA.py.
It seems to be the ldap lib internal error, but why does it only happen in flask and how could I fix it?
Thanks guys!
Turns out it was a unicode problem, for anyone having the same error:
Go to ldpaobject.py(whererver you have python-ldap installed)
Change
if PY2:
text_type = unicode
else:
text_type = str
to just
text_type = str
python-ldap should now work in flask

TypeError: Expecting a string- or bytes-formatted key when using Flask-JWT

I have a question about flask python.
I tried learning how to build a web using flask, and there is some error. In this case I am using mongoengine as database and JWT(Json Web Token) and the alert error is like this: "TypeError: Expecting a string- or bytes-formatted key"
192.168.100.26 - - [22/Nov/2016 22:50:08] "POST /auth HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/home/def/.local/lib/python2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/def/pr/flask/flask_deeper/test/routes/auth.py", line 26, in auth
access_token = _jwt.jwt_encode_callback(identity)
File "/usr/local/lib/python2.7/dist-packages/flask_jwt/__init__.py", line 70, in _default_jwt_encode_handler
return jwt.encode(payload, secret, algorithm=algorithm, headers=headers)
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jwt.py", line 56, in encode
json_payload, key, algorithm, headers, json_encoder
File "/usr/local/lib/python2.7/dist-packages/jwt/api_jws.py", line 98, in encode
key = alg_obj.prepare_key(key)
File "/usr/local/lib/python2.7/dist-packages/jwt/algorithms.py", line 116, in prepare_key
raise TypeError('Expecting a string- or bytes-formatted key.')
TypeError: Expecting a string- or bytes-formatted key.
I thought the error was at this.
models/user.py
#staticmethod
def jwt_handler(token):
if not User.objects(token=token):
raise JWTError("Bad bad bad bad")
secret = str(current_app.config["JWT_SECRET_KEY"])
algorithm = str(current_app.config["JWT_ALGORITHM"])
options = {
'verify_' + claim: True
for claim in verify_claims
}
options.update({
'require_' + claim: True
for claim in required_claims
})
decode = jwt.decode(token, secret, options=options, algorithms=[algorithm])
return decode
#staticmethod
def authenticate(username, password):
user = User.objects(username=username)
if len(user) == 0:
return None
user = user[0]
user["id"] = str(user["id"])
if crypt.verify(password, user.password):
return user
return user
routes/user.py
def auth():
username = request.form.get("username")
password = request.form.get("password")
if not username:
raise BadRequest("Userna doesn't exists")
user = user_ctrl.read(username)
identity = _jwt.authentication_callback(username, password)
if identity:
access_token = _jwt.jwt_encode_callback(identity)
identity.update(push__token=access.decode("utf8"))
return _jwt.auth_response_callback(access_token, identity)
else:
raise JWTError("Bad bad bad very bad")
config.py
import os
from test.models import db
class Config(object):
db_name = os.getenv('MONGODB_NAME', 'third')
db_host = os.getenv('MONGODB_HOST', '127.0.0.1')
db_port = os.getenv('MONGODB_PORT', '5000')
JWT_SECRET_KEY = 'test123'
JWT_ALGORITHM = 'SH256'
JWT_AUTH_ENDPOINT = 'jwt'
JWT_AUTH_USERNAME_KEY = 'username'
JWT_AUTH_PASSWORD_KEY = 'password'
http.py
import logging.config
import jwt
from flask_jwt import JWT
from flask import Flask
from test import routes
from test.models import db, User
_jwt = JWT(authentication_handler=User.authenticate, identity_handler=User.identity)
_jwt.jwt_decode_callback=User.jwt_handler
def create_app(config):
app = Flask(__name__.split(',')[0])
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
You have defined the configuration is config.py but have not added the configuration object to your flask app. Therefore, keys such as JWT_SECRET_KEY are not in your app config.
Flask-JWT's default_handler expects those values (Copied in case source changes)
def _default_jwt_decode_handler(token):
secret = current_app.config['JWT_SECRET_KEY']
algorithm = current_app.config['JWT_ALGORITHM']
leeway = current_app.config['JWT_LEEWAY']
In your case as that is not set, it returns None and trips the algorithms.py (which expects a string key).
Therefore, during your app initialization in http.py, you must add a call to app.config.from_object. Maybe something like this
def create_app(config):
app = Flask(__name__.split(',')[0])
# Edit the following to point it to your Config class
app.config.from_object(config.Config)
app.register_blueprint(routes.user.bp)
app.register_blueprint(routes.auth.bp)
db.init_app(app)
_jwt.init_app(app)
return app
On a side note, the name of JWT_ALGORITHM should be HS256 rather than SH256 (Although it doesn't matter as HS256 is the default and will be chosen since SH256 is not a valid algorithm)

Categories