I have a question about flask error handler.
When I want to handle 404 error I use this code:
#app.errorhandler(404)
def page_not_found(e):
return render_template("404.html")
Why I should pass the (e) to the function?
Thanks! :)
e is the exception raised, triggering the handler to be called.
You can register the same error handling function for multiple error codes, and you can use that argument passed in to determine exactly for what error it was called or use that code in a generic template:
#application.errorhandler(404)
#application.errorhandler(401)
#application.errorhandler(500)
def http_error_handler(error):
return render_template("error.html", error=error)
From the Error Handlers documentation:
An error handler is a function, just like a view function, but it is called when an error happens and is passed that error.
Bold emphasis mine.
Note that it is an exception instance; for HTTP error codes, that'll be an instance of a subclass of the HTTPException class (Werkzeug defines several such subclasses). Such instances have a .code attribute if you really want to match against the HTTP code:
if error.code == 404:
# not found error
I'm guessing it is holding the exception so if you want to return it to know what went wrong. Though I am not familiar with this, or it if it is a parent it may need an argument supplied to it to check the error and handle it properly.
Related
Background
In Python it is possible to suppress the context of an Exception if you raise your Exception from None. PEP 409 describes the rationale behind it. Sometimes you want to show only one meaningful (custom) Exception. With PEP 415 the implementation changes with the following argument:
The main problem with this scheme [from PEP 409] is it complicates the role of __cause__. __cause__ should indicate the cause of the exception not whether __context__ should be printed or not. This use of __cause__ is also not easily extended in the future. For example, we may someday want to allow the programmer to select which of __context__ and __cause__ will be printed.
Question
PEP 419 talks about future use cases. Are there any valid use cases right now (Python 3.3+) for using an alternative exception cause? For example, consider the following code:
class CustomError(BaseException):
pass
class StupidError(BaseException):
def __init__(self, message='This is just a stupid error.'):
super(StupidError, self).__init__(message)
self.message = message
try:
value = int('a')
except Exception:
raise CustomError('Custom error message') from StupidError
Output:
StupidError: This is just a stupid error.
The above exception was the direct cause of the following exception:
Traceback (most recent call last): (...)
CustomError: Custom error message
Are there any real use cases in which you want to hide the ValueError but show the StupidError? I mean you could give some relevant information in the StupidError which are not present in a mere ValueError? Maybe I am just overthinking this whole thing.
Sure. Say you're writing a web app and need to hide sensitive/complicated data from the user.
Say a user tries a request, but the web app backend has trouble reading the necessary data from a MySQL database (for whatever reason). Instead of letting the MySQL module raise the error, which could either expose sensitive information about how the app works internally or just simply confuse the user, I would want to catch it and then throw my custom exception (let's call it serverError). That custom exception would show the user a HTTP 500 page as well as report the error internally so it can be analyzed by a developer to figure out what went wrong and how to prevent it.
This means I only have to write my general error handling code once, and then when I catch an error, I can raise serverError, which takes care of the error reporting for me.
After much googli searching to figure out whats going on, here it is:
I have a custom validation exception which takes a request and response
class ValidationException(Exception):
message = "Caught Validation Exception"
def __init__(self, request, response):
self.details = {
"request": request,
"response": response
}
super(ValidationException, self).__init__(self.message, self.details)
I have an exception handler which will raise an instance of it on some condition:
class handler:
if something:
raise ValidationException(request, response)
The handler is called in the event we encounter an issue in a post
class Poster:
def post(data):
if self.last_response.status_code not in self.valid_post_codes:
self.exception_handler.handleException(self.last_request, self.last_response)
The problem is, I'm raising the ValidationException, getting it in my traceback, but, it doesn't seem to get caught where I want it.
def testThis(self):
try:
self.poster.post(json.dumps({}))
except ValidationException:
print "got validation"
except Exception:
print "got exception"
Result: "got exception"
traceback
lib/service/pas/api/order.py line 24 in postOrder
return self.post()
lib/service/base.py line 42 in post
self.exception_handler.handleException(self.last_request, self.last_response)
lib/service/exception/handler.py line 14 in handleException
raise ValidationException(request, response)
ValidationException:
For what its worth:
assertRaises(ValidationException, self.poster.post, json.dumps({}))
only catches Exception as well. Any ideas? :\ Any help is greatly appreciated! Thanks in advance
Well well well... So..
My IDE prefixed my import with "lib" which imported Exceptions.ValidationException.
When I throw my.own.ValidationException elsewhere, it wasn't being caught as it wasn't of the same type. Just so turned out there happened to be another ValidationException I didn't know about...
Thats amazing, NOT!
I could not replicate it with the code given, but two suspicious places to consider:
You seem to be mixing old-style and new-style classes. That can lead to subtle bugs. Try class Handler(object):, class Poster(object): and in all other instances make classes new-style classes that are explicit subclasses of object.
You seem to have a complex exception invocation mechanism, with
self.exception_handler.handleException(self.last_request, self.last_response)
Why not just:
raise ValidationException(self.last_request, self.last_repsonse)
right there? At least as a debugging experiment, remove or short-circuit modules, functions, and code you're not sure about or isn't preven to work. Cut to the chase, see if you can fix the behavior. At least, it might help you narrow down where the problem is. If it's in the handler, you can then choose to either fix it or chuck it.
I would like to disable the stack trace that is printed when there is an exception raised.
Whenever the code calls the logger.exception method, the stack trace is automatically printed.
That's because the default value of the exc_info parameter of the .exception method is True.
See the source code:
def exception(msg, *args, exc_info=True, **kwargs):
"""
Log a message with severity 'ERROR' on the root logger, with exception
information. If the logger has no handlers, basicConfig() is called to add
a console handler with a pre-defined format.
"""
error(msg, *args, exc_info=exc_info, **kwargs)
To prevent this, you can send exc_info=False to the .exception method like this:
try:
raise Exception("Huston we have a problem!")
except Exception as ex:
logger.exception(f"Looks like they have a problem: {ex}", exc_info=False)
While this seems like working, it is bad to force users to write exc_info=False each time they use that method. Therefore, in order to take this burden from the shoulders of the programmers, you can monkey patch the .exception method and make it act like a regular .error method like this:
# somewhere in the start of your program
# money patch the .exception method
logger.exception = logger.error
try:
raise Exception("Huston we have a problem!")
except Exception as ex:
logger.exception(f"Looks like they have a problem: {ex}")
Looking around I found the following solution / workaround:
sys.tracebacklimit = 0
Using unittest to test some edge cases with an API. All of these cases return 400-series response codes using custom exception classes. Unfortunately, I can't seem to find a way to catch these custom exceptions or to read the response codes in the unittest check itself.
What I have been receiving is an 'AppError' exception with a message mentioning it is a 400 response rather than a 200 or 300. I want to avoid parsing the exception message if I can. This also needs to work on Python 2.6+. How can I either catch the custom exceptions in my unittest check, or determine the response code causing the error without parsing the exception message?
You'll have to catch the exception and assert that it is not a 400 response:
try:
call_api_method()
except AppError as ae:
self.assert(ae.errorcode < 400)
This requires the exception to carry the error code as an attribute; you perhaps need to inspect what attributes are available on the exception. By default .args will be there (it is a tuple), but it is good practice for such exceptions to have an error code attribute too.
I figured out how to do this. Turns out that with webtest (which I forgot to mention as being used), you can pass in a parameter expect_errors=True and save the return value of the request. You can then check against the response status with
self.assertEqual('400 Bad Request', response.status)
I am trying to assertRaise the exception inside a function where a condition raises a custom exception message .
Function:
if not Cart.objects.filter(member=member).count():
raise CartDoesNotExist("Cart Does Not Exist for Member: %s ( %id )." % (member.email,member.id))
Now , i am able to successfully produce the required condition to get to the raise statement.
So , my testcase looks like this :
def Order_CartDoesNotExist(self):
self.assertRaises(CartDoesNotExist,Order.objects.create_order(member=self.member2,member_slot=self.memslot,order_type="Normal"))
When i run the test , the output is an Error . It gives the same error CartDoesNotExist.....
So my question is , how to raise these kind of exceptions ? How to cover these situations in our unittest? I do not want to escape these conditions as they are important and increase code coverage?
Thank you all.
Your code is calling create_order directly, which raises the exception. You need to change how it is called. In Python 2.7, you can use this:
with self.assertRaises(CartDoesNotExist):
Order.objects.create_order(member=self.member2, member_slot=self.memslot, order_type="Normal"))
Here the context manager allows you to call your code directly, and the context manager will handle the exception for you.
If you are running with 2.6 or below:
self.assertRaises(CartDoesNotExist, Order.objects.create_order, member=self.member2, member_slot=self.memslot, order_type="Normal")
Here you aren't calling your function, you are passing it to assertRaises, along with the arguments it needs, and assertRaises will call the code and deal with the exception properly.