What is the base exception for an invalid JWT in PyJWT? - python

According to the documentation for PyJWT, the class jwt.exceptions.InvalidTokenError is the base error when the decode method fails. However, the following code still breaks with different exceptions:
try:
jwt.decode(jwt_token, os.environ['SECRET'], algorithms="HS256")
except jwt.exceptions.InvalidTokenError:
pass
My thinking was that since InvalidTokenError is the base error, this except block should catch all the other possible PyJWT errors such as InvalidSignatureError, DecodeError etc. My question is if there is a base error for PyJwt I could use. I know using except Exception is always an option but that's bad form so I'd like to avoid it if possible. Thanks!

I got this micro example working. In general, don't pass an exception, at least print the error message.
#pip install pyjwt
import os, jwt, hashlib
jwt_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.VUI28NztICBIB9m6kZolIEzYJojrw0eUr_4bVoQ1Ong"
os.environ['SECRET'] = hashlib.sha256(b"0").hexdigest()
try:
print(jwt.decode(jwt_token, os.environ['SECRET'], algorithms="HS256"))
except jwt.exceptions.InvalidTokenError as e:
print(repr(e))
except Exception as e:
print("WARNING NORMAL EXCEPTION CAUGHT")
print(repr(e))
Output:
{'sub': '1234567890', 'name': 'John Doe', 'iat': 1516239022}
Which error was raised? My best guess is that you have another problem. KeyError for Secret, is not an error related to jwt:
WARNING NORMAL EXCEPTION CAUGHT
KeyError('SECRET')
If your token is incorrect, you get this:
DecodeError('Not enough segments')
And if your signare is not correct, this:
InvalidSignatureError('Signature verification failed')

Related

Python Exception block not working for MQMIError - MQRC_NO_MSG_AVAILABLE

I have wrote below exception in my Python code while doing "get" message from MQ. However when records are getting PUT on MQ by another application & at the same time I am running my code it's failing with error:
pymqi.MQMIError: MQI Error. Comp: 2, Reason 2033: FAILED: MQRC_NO_MSG_AVAILABLE
Although below exception is handled it'snot working. Can you please suggest if below exception is wrong OR provide me correct code?
except pymqi.MQMIError as e:
if e.comp == pymqi.CMQC.MQCC_FAILED and e.reason == pymqi.CMQC.MQRC_NO_MSG_AVAILABLE:
pass # No messages, that is OK, we can ignore it.
else:
raise # Some other error condition.

Consider explicitly re-raising using the 'from' keyword pylint suggestion

I have a small python code in which I am using exception handling.
def handler(event):
try:
client = boto3.client('dynamodb')
response = client.scan(TableName=os.environ["datapipeline_table"])
return response
except Exception as error:
logging.exception("GetPipelinesError: %s",json.dumps(error))
raise GetPipelinesError(json.dumps({"httpStatus": 400, "message": "Unable to fetch Pipelines"}))
class GetPipelinesError(Exception):
pass
pylint warning gives me " Consider explicitly re-raising using the 'from' keyword ".
I saw few other posts, where they used from and raised an error. I made modifications like this
except Exception as GetPipelinesError:
logging.exception("GetPipelinesError: %s",json.dumps(GetPipelinesError))
raise json.dumps({"httpStatus": 400, "message": "Unable to fetch Pipelines"}) from GetPipelinesError
Is this the right way to do ?
No. The purpose of raise-from is to chain exceptions. The correct syntax in your case is:
except Exception as error:
raise GetPipelinesError(json.dumps(
{"httpStatus": 400, "message": "Unable to fetch Pipelines"})) from error
The expressions that follow raise and from must be exception classes or instances.

How to catch an exception in for loop but at the end throw one?

I want to catch an Exception in a for loop, and print a message in all items of the for loop, but at the end, still throw an Exception, so that I know the script failed. How to do that?
I'm trying this for now:
for key, value in marketplaces.items():
try:
r = requests.post(value, data=json.dumps({'Content': message(key, res)}), verify=False)
except:
r = requests.post(value, data=json.dumps({'Content': "Sorry, an error occured"}), verify=False)
But with this code, I only catch the exception and post an error message to all items in the for loop, but don't know that the script failed. I want to know this and throw and exception, after posting an error message to all items in for loop.
Any suggestions? Thank you!
The idea is to set a variable inside the except clause and check it after the loop is done. The example below is roughly what you need.
Note that there could be more than one failure, so we use a list to store all the errors, and report them all at the end.
Also note that the correct way to catch an exception in Python is to catch a specific exception -- in this case, it suffices to catch the requests.exceptions base class.
The code below stores the exception string e in the list of errors and afterwards, we check if there are any errors, and raise a new exception with the entire list of errors.
In this case, we're just raising the most generic exception type for requests exceptions -- requests.exceptions.RequestException (i.e. the base class once again). This is because there are various possible errors which could have occurred during the requests. Depending on your use case, you might prefer another more standard exception type, such as RuntimeError -- see the docs for the standard exception types.
import requests
errors = []
for key, value in marketplaces.items():
try:
r = requests.post(value, data=json.dumps({'Content': message(key, res)}), verify=False)
except requests.exceptions.RequestException as e:
r = requests.post(value, data=json.dumps({'Content': "Sorry, an error occured"}), verify=False)
errors.append(str(e))
if errors:
raise requests.exceptions.RequestException(errors)
Alternative:
Though the above is a fairly common approach that suits many use cases, it may be convoluted in some situations. Hence, I'm proposing a much simpler and more trivial alternative, which may also suit your needs, or anyone else who stumbles across this. Simply print out an error message each time an exception is raised (i.e. each time the code enters the except clause), like this:
import requests
import sys
for key, value in marketplaces.items():
try:
r = requests.post(value, data=json.dumps({'Content': message(key, res)}), verify=False)
except requests.exceptions.RequestException as e:
r = requests.post(value, data=json.dumps({'Content': "Sorry, an error occured"}), verify=False)
print(str(e), file=sys.stderr)
Hope this helps!

Advice on Pyramid views exception handling

There are three situations when I need to handle exceptions.
When data validation raised exception
When library/module functions raised exceptions (e.g. database connection abort)
When business logic raises exception such as 500, 503, 401, 403 and 404
def library_func():
try:
...
except HTTPException:
raise TwitterServiceException("Twitter is down!")
#view_config(route_name="home", renderer="json")
#validator
#authorization
def home_view(request):
try:
tweets = library_func()
return {"tweets": tweets}
except TwitterServiceException as e:
LOG.critical(e.msg)
raise ParnterServcieError(e.msg) # this is probably a 503 error
def validator(args):
# I will show the high level of this decorator
try:
decode input as JSON
verify data format
except ValueError as err:
error = {'error': "Missing required parameters."}
except json.JSONDecodeError as err:
error = {'error': "Failed to decode the incoming JSON payload."}
if error is not None:
return HTTPBadRequest(body=json.dumps(error),
content_type='application/json')
def authorization(args):
# very similar to validator except it performs authorization and if failed
# 401 is raised with some helpful message.
The doc suggests Custom Exception Views. In my PoC above, I will tie ParnterServcieError as one. I can even generalize HTTPBadRequest and all praymid.httpexceptions using custom exception so that I no longer need to repeat json.dumps and content_type. I can set a boilerplate error body before I return request.response object.
Idea:
#view_config(context=ParnterServcieError)
def 503_service_error_view(e, request):
request.response.status = 503
request.response.json_body = {"error": e.msg}
return request.response
I can generalize one for all uncaught, unspecified exceptions (which results in 500 Internal Server Error) called 500_internal_server_error_view.
Does this seem sane and clean to people? Is my way of handling high and low level of exceptions proper and Pythonic?
I applied this strategy to ToDoPyramid and could encapsulate error handling in a single custom exception view that was repeated multiple times in the application before. Until you could even improve it, you got a great idea. Pyramid rocks.
References
Catching database connection error in ToDoPyramid

Catching a jira-python exception

I am trying to handle jira-python exception but my try, except does not seem to catch it. I also need to add more lines in order to be able to post this. So there they are, the lines.
try:
new_issue = jira.create_issue(fields=issue_dict)
stdout.write(str(new_issue.id))
except jira.exceptions.JIRAError:
stdout.write("JIRAError")
exit(1)
Here is the code that raises the exception:
import json
class JIRAError(Exception):
"""General error raised for all problems in operation of the client."""
def __init__(self, status_code=None, text=None, url=None):
self.status_code = status_code
self.text = text
self.url = url
def __str__(self):
if self.text:
return 'HTTP {0}: "{1}"\n{2}'.format(self.status_code, self.text, self.url)
else:
return 'HTTP {0}: {1}'.format(self.status_code, self.url)
def raise_on_error(r):
if r.status_code >= 400:
error = ''
if r.text:
try:
response = json.loads(r.text)
if 'message' in response:
# JIRA 5.1 errors
error = response['message']
elif 'errorMessages' in response and len(response['errorMessages']) > 0:
# JIRA 5.0.x error messages sometimes come wrapped in this array
# Sometimes this is present but empty
errorMessages = response['errorMessages']
if isinstance(errorMessages, (list, tuple)):
error = errorMessages[0]
else:
error = errorMessages
elif 'errors' in response and len(response['errors']) > 0:
# JIRA 6.x error messages are found in this array.
error = response['errors']
else:
error = r.text
except ValueError:
error = r.text
raise JIRAError(r.status_code, error, r.url)
I know I'm not answering the question, but I feel I need to warn people that could get confused by that code (as I did)...
Maybe you are trying to write your own version of jira-python or it's an old version?
In any case, here the link to the jira-python code for the JIRAError class
and here the list of codes
to catch the exception from that package I use the below code
from jira import JIRA, JIRAError
try:
...
except JIRAError as e:
print e.status_code, e.text
Maybe it is obvious and that's why you don't have it in your code paste, just in case, you do have
from jira.exceptions import JIRAError
somewhere in your code right?
Don't have enough reputation for comments so I'll add it answer for #arynhard:
I found the docs very light in particular in terms of example, you might find the scripts in this repo useful since they're all leveraging jira-python in someway or another.
https://github.com/eucalyptus/jira-scripts/
I might be wrong, but looks like you're catching jira.exceptions.JIRAError, while raising JIRAError - those are different types. You need to either remove "jira.exceptions." part from your except statement, or raise jira.exceptions.JIRAError instead.
Ok it's a very old one but I faced the same problem and this page is still showing up.
Here is how I trap the Exception, I used the Exception object.
try:
issue = jira.issue('jira-1')
except Exception as e:
if 'EXIST' in e.text:
print 'The issue does not exist'
exit(1)
regards

Categories

Resources