Flask-restful - During handling of the above exception, another exception occurred - python

As part a Flask-restful API I have a login Resource:
class LoginApi(Resource):
def post(self):
try:
body = request.get_json()
user = User.objects.get(email=body.get('email'))
authorized = user.check_password(body.get('password'))
if not authorized:
raise UnauthorizedError
expires = datetime.timedelta(days=7)
access_token = create_access_token(identity=str(user.id), expires_delta=expires)
return {'token': access_token}, 200
except DoesNotExist:
raise UnauthorizedError
except Exception as e:
raise InternalServerError
There are 4 scenarios for login route:
Email and Password are correct
Email does not exist in the database - in this case the UnauthorizedError is raised correctly.
Email exists but password is incorrect - in this case I have an issue (described below)
Some other Error - InternalServerError is raised correctly.
So for number 3 - instead of getting an UnauthorizedError, I am getting an InternalServerError.
The if not authorized: statement is working correctly (If i put a print in there I can see it work). However for some reason I am getting the following when trying to raise the error:
During handling of the above exception, another exception occurred:
I came across this PEP article which seems to suggest changing to raise UnauthorizedError from None but the issue persists. Does anyone know how I can implement this successfully? Ideally I would like the same error to be raised from scenarios 2 and 3, otherwise there is a potential for someone to know whether or not an email exists in the database, from the errors they get back.

The if statement is raising UnAuthorized, but that happens in the excepts, you have to raise DoesNotExist to make it so that UnAuthorized can be raised in the except.

Related

Minio minio.error.SignatureDoesNotMatch thrown with try-except

I am using the python package for the minio server. I have the following piece of code that is used for a login:
from minio.error import [...], SignatureDoesNotMatch, [...]
def login(self):
try:
self.user = Minio(MINIO_CONFIG['MINIO_ENDPOINT'],
access_key=self.username,
secret_key=self.password,
secure=MINIO_CONFIG['MINIO_SECURE'])
return {"msg":"User is now logged in", "status": "OK"}
except SignatureDoesNotMatch as err:
return {"msg": err.message, "status":"F"}
except ResponseError as err:
return {'msg': err.message, 'status': "F"}
except InvalidAccessKeyId as err:
return {"msg": err.message, "status":"F"}
except InvalidArgument as err:
return {"msg": err.message, "status":"F"}
except InvalidArgumentError as err:
return {"msg": err.message, "status":"F"}
The issue I am facing is that even though I do have in the try-except the SignatureDoesNotMatch in case the credentials are not correct, it does not return me the msg it should but it throws an minio.error.SignatureDoesNotMatch instead. Why does that happen?
The error I get:
minio.error.SignatureDoesNotMatch: SignatureDoesNotMatch: message: The request signature we calculated does not match the signature you provided.
This seems fine, looking at the code, this will never run into an error on it's own, regardless of the credentials provided. It will only run into an error when it makes an API call, or when you invoke methods like list_buckets, list_objects etc using this self.user instance, from outside this block.
I think what you're trying to do is-- invoking methods like list_buckets etc from outside this encapsulation-- somewhere else not this part of the code, and then they produce this error and propagate them to the console. You cannot encapsulate the MinIO instance within try-catch and catch errors while you make use of stuff like self.user.list_buckets() from outside this try-catch block.

Using OpenStack Nova Exceptions

When I'm using nova.keypairs.create() and I pass it an invalid public key, I get the following:
BadRequest: Keypair data is invalid: failed to generate fingerprint (HTTP 400) (Request-ID: req-12bc6440-f042-4687-9ee9-d89e7edc260d)
I tried doing the following and for obvious reasons (it's a unique exception to OpenStack) it didn't work:
try:
nova.keypairs.create(name=keyname, public_key=key)
except BadRequest:
raise cherrypy.HTTPError(400, "Invalid public key")
How can I use OpenStack specific exceptions such as BadRequest within my own try and except statements?
You will need to import the exceptions for nova package. Going through github for the package, it looks like you will need to do:
from nova.exception import *
Note that the exception you are seeing is actually InvalidKeypair exception, which itself subclasses from exception class Invalid, the BadRequest message is just the template text for it.
So, your complete code would look something like:
from nova.exception import *
# You can import specific ones if you are confident about them
try:
nova.keypairs.create(name=keyname, public_key=key)
except InvalidKeypair:
raise cherrypy.HTTPError(400, "Invalid public key")

How to understand how exception handling is working?

I have been fiddling around with raising exceptions for Google Big Query. I finally figured out how to make it work in the way it should work, but I don't really understand why it works. I am looking to gain a better understanding what is going on in my code. I have already scoured Stack Overflow and nothing seems to help.
Here is my view:
#api_view(['POST'])
def delete_table(request): # Deletes table from Big Query
project_id = request.POST.getlist('data[]')[0]
dataset_id = request.POST.getlist('data[]')[1]
table_id = request.POST.getlist('data[]')[2]
bq = BigQuery(project_id) # Instantiates BQ instance specific to project id
try:
bq.deleteTable(dataset_id, table_id) # Calls deleteTable method from BQ instance
except Exception, res:
logger.debug(res)
return Response('')
Here is my delete method in my Big Query controller:
def deleteTable(self, datasetId, tableId):
try:
response, content = \
self.http_auth.request("https://www.googleapis.com/bigquery/v2/projects/%s/datasets/%s/tables/%s" % (self.PROJECT_ID, datasetId, tableId), "delete")
content = json.loads(content)
message = content['error']['message']
raise Exception, message
except:
if response.status < 300:
message = tableId + " Was Deleted."
raise Exception, message
else:
raise Exception, message
I understand that the view is catching a raised error from the bqcontroller, I don't understand how the errors are being raised in the bqcontroller. Could someone please shed some light?
As the code is, there is no real reason for the try because at the end of the try block you always raise an exception, so you always go to the except block. So each time the code runs, it goes through the try, then hits the exception so goes to the except block where it raises an exception no matter which branch of the if/else statement you go to.
This code here does the same thing, it's just a little cleaner (less duplication) so you can see where the exceptions are being raised
def deleteTable(self, datasetId, tableId):
GOOG_API_ENDPOINT = 'https://www.googleapis.com/bigquery/v2/projects/{}/datasets/{}/tables/{}'
url = GOOG_API_ENDPOINT.format(self.PROJECT_ID, datasetId, tableId)
response, json_content = self.http_auth.request(url, "delete")
content = json.loads(json_content) # don't reassign same variable name
if response.status < 300:
message = tableId + " Was Deleted."
raise Exception, message # exception raised here or in else below
else:
message = content.get('error', {}).get('message')
raise Exception, message
Although I wouldn't raise a generic Exception, I'd use one of the built-ins or define your own

tweepy/ twitter api error type

I am using tweepy to make a twitter application.
When users tweet/update profile, etc, they will get some errors. I want to classify error and give user more information.
try:
tweet/update profile/ follow....
except tweepy.TweepError, e:
if tweepy.TweepError is "Account update failed: Description is too long (maximum is 160 characters)"
Do something
if tweepy.TweepError is "Failed to send request: Invalid request URL: http://api.twitter.com/1/account/update_profile.json?location=%E5%85%B5%E5%BA%A"
Do something
if tweepy.TweepError is "[{u'message': u'Over capacity', u'code': 130}]"
Do something
Is the only way to classify error is to compare e with string, for example, Account update failed: Description is too long (maximum is 160 characters)?
Right, it is the only way now. There is only one TweepError exception defined. It's raised throughout the app with different text.
Here's the relevant open issue on github. So there is a chance that it'll be improved in the future.

Python: Getting the error message of an exception

In python 2.6.6, how can I capture the error message of an exception.
IE:
response_dict = {} # contains info to response under a django view.
try:
plan.save()
response_dict.update({'plan_id': plan.id})
except IntegrityError, e: #contains my own custom exception raising with custom messages.
response_dict.update({'error': e})
return HttpResponse(json.dumps(response_dict), mimetype="application/json")
This doesnt seem to work. I get:
IntegrityError('Conflicts are not allowed.',) is not JSON serializable
Pass it through str() first.
response_dict.update({'error': str(e)})
Also note that certain exception classes may have specific attributes that give the exact error.
Everything about str is correct, yet another answer: an Exception instance has message attribute, and you may want to use it (if your customized IntegrityError doesn't do something special):
except IntegrityError, e: #contains my own custom exception raising with custom messages.
response_dict.update({'error': e.message})
You should use unicode instead of string if you are going to translate your application.
BTW, Im case you're using json because of an Ajax request, I suggest you to send errors back with HttpResponseServerError rather than HttpResponse:
from django.http import HttpResponse, HttpResponseServerError
response_dict = {} # contains info to response under a django view.
try:
plan.save()
response_dict.update({'plan_id': plan.id})
except IntegrityError, e: #contains my own custom exception raising with custom messages.
return HttpResponseServerError(unicode(e))
return HttpResponse(json.dumps(response_dict), mimetype="application/json")
and then manage errors in your Ajax procedure.
If you wish I can post some sample code.
Suppose you raise error like this
raise someError("some error message")
and 'e' is catched error instance
str(e) returns:
[ErrorDetail(string='some error message', code='invalid')]
but if you want "some error message" only
e.detail
will gives you that (actually gives you a list of str which includes "some error message")
This works for me:
def getExceptionMessageFromResponse( oResponse ):
#
'''
exception message is burried in the response object,
here is my struggle to get it out
'''
#
l = oResponse.__dict__['context']
#
oLast = l[-1]
#
dLast = oLast.dicts[-1]
#
return dLast.get( 'exception' )

Categories