I'm trying to setup email error logging and I want to test it.
Whats an easy way to trigger a 500 error in Django? This surprisingly has not been discussed here yet.
A test view like this will work:
from django.http import HttpResponse
def my_test_500_view(request):
# Return an "Internal Server Error" 500 response code.
return HttpResponse(status=500)
or use the baked in error class:
from django.http import HttpResponseServerError
def my_test_500_view(request):
# Return an "Internal Server Error" 500 response code.
return HttpResponseServerError()
Raising an appropriate Exception is the most robust way to test this. Returning an HttpResponse of any variety, as in #agconti 's answer, will not allow you to test the behavior of error handling. You'll just see a blank page. Raising an exception triggers both the correct response code and the internal Django behavior you expect with a "real" error.
Response code 500 represents the server not knowing what to do. The easiest way is to write into your test or test-view raise Exception('Make response code 500!').
Most other errors should be raised with exceptions designed to trigger specific response codes. Here's the complete list of Django exceptions that you might raise.
Old question, but I hope this helps someone in the future. The accepted answer doesn't really answer the original question...
You can do this with django rest framework easily by raising ApiException:
from rest_framework.exceptions import APIException
try:
...
except ...:
raise APIException('custom exception message')
This will return a response with status 500 from your view. Pretty useful if you are calling another function from your API and you don't want to manage return values from this function to decide if returning a response with status 500.
You can use it like this:
raise ApiException
And the default response message (at the time of writing this) will be 'A server error occurred.'.
There's a few predefined ApiException subclasses to raise different kinds of errors, check the file rest_framework.exceptions, if you need one that is not in there, you can extend ApiException like this:
from rest_framework.exceptions import APIException
class YourCustomApiExceptionName(APIException):
def __init__(self, status, detail):
self.status_code = status
self.detail = detail
Usage:
raise YourCustomApiExceptionName(100, 'continue')
You can also define custom status and detail but wouldn't make much sense in most cases.
Related
I have a Flask server.
Whenever the code inside my handler throws an exception, Flask catches it, and returns an HTML page to the client with a 5XX error.
The problem is that I don't notice this. I just got an email from someone using my API saying that they were getting 504 errors, and I didn't know about it until they told me.
In other non-Flask parts of my application I wrote a custom decorator to catch all exceptions, send an email to me, then re-throw. I would like something similar for my Flask app.
I want to find a way to have Flask call a function of mine every time my handler code throws an exception, before it returns a response to the client. I do not wish to modify the response that gets sent to the client. I don't want to change how Flask handles errors, or how it catches them. I just want some way of being notified, and then Flask can continue doing the default error handling behavior.
I suppose I could put a decorator over every single route handler to catch and rethrow exceptions before Flask sees them, but that's messy. I just know I'll forget one of them, especially when I add new ones in the future.
MWE
A buggy application:
from flask import Flask
app = Flask(__name__)
#app.route("/")
def hello():
assert False, "buggy code here"
return "hello"
def error_handler(exc_type, exc_val, exc_tb):
send_email(exc_type, exc_val, exc_tb)
# This is the part I don't know
# I want something along the lines of:
app.config['ERROR_HOOK'] = error_handler
from flask import Flask
app = Flask(__name__)
app.debug = False
app.config['PROPAGATE_EXCEPTIONS'] = True
#app.errorhandler(Exception)
def all_exception_handler(error):
print(str(error))
#app.errorhandler(404)
def page_not_found(error):
return 'This page does not exist', 404
you can define a function for each specific error you want to catch #app.my_custom_errorhandler(code_or_exception)
The argument to your error handler function will be an Exception.
The Locust documentation explains that a request can be prevented from being logged by using a context manager and raising an exception. For example:
try:
with self.client.get('/wont_be_logged', catch_response=True) as response:
raise RuntimeError
catch RuntimeError
pass
Is there a way to achieve the same without having to use a context manager?
Just do the request yourself (without using self.client)
For example by using requests.get(...)
(note that this will use a different session so it wont use the same cookies or underlying http connection)
Not detract from cyberwiz's answer as ultimately you could just do your own requests and get the same behavior, but if you really want to just use Locust's client and not manage another client yourself, you can. catch_response=True should be enough for it to not automatically fire success or failure Events. You can then manually fire events with whatever you want after that.
Demo Locust file:
from locust import HttpUser
from locust.user.task import task
class TestUser(HttpUser):
host = "http://localhost:8089"
#task
def test_call(self):
r = self.client.get("/", catch_response=True)
print("Test")
print(r.elapsed)
self.environment.events.request_success.fire(
request_type="POST",
name="/somewhere_new",
response_time=r.elapsed.microseconds / 1000,
response_length=13,
)
Again, doing it this way doesn't save much it works.
I have a helper method in a Flask app that is used by several endpoints to get a resource. To avoid having multiple redirect_url calls everywhere, I want to be able to redirect from just this helper method. Throwing a RequestRedirect exception as shown here correctly returns a 301 response, but doesn't set the Content-Location error. To get around this, I added a after_this_request hook that sets the url for that response.
This seems to work correctly, but I was wondering if theres a more elegant way to go about it.
Anonymized helper method:
def get_resource(resource_id):
try:
# Some logic
except:
#after_this_request
def add_header(response):
response.headers['Content-Location'] = url
return response
raise RequestRedirect(new_url='/')
If it is outside of your api, typically you would redirect to a 404 page. Here's a sample:
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
I'm using Python and Webtest to test a WSGI application. I found that exceptions raised in the handler code tend to be swallowed by Webtest, which then raises a generic:
AppError: Bad response: 500 Internal Server Error
How do I tell it to raise or print the original error that caused this?
While clj's answer certainly works, you may still want to access the response in your test case. To do this, you can use expect_errors=True (from the webtest documentation) when you make your request to the TestApp, and that way no AppError will be raised. Here is an example where I am expecting a 403 error:
# attempt to access secure page without logging in
response = testapp.get('/secure_page_url', expect_errors=True)
# now you can assert an expected http code,
# and print the response if the code doesn't match
self.assertEqual(403, response.status_int, msg=str(response))
Your WSGI framework and server contains handlers which catch exceptions and performs some action (render a stacktrace in the body, log the backtrace to a logfile, etc). Webtest, by default, does not show the actual response, which might be useful if your framework renders a stacktrace in the body. I use the following extension to Webtest when I need to look at the body of the response:
class BetterTestApp(webtest.TestApp):
"""A testapp that prints the body when status does not match."""
def _check_status(self, status, res):
if status is not None and status != res.status_int:
raise webtest.AppError(
"Bad response: %s (not %s)\n%s", res.status, status, res)
super(BetterTestApp, self)._check_status(status, res)
Getting more control over what happens to the exception depends on what framework and server you are using. For the built in wsgiref module you might be able to override error_output to achieve what you want.
I've recently started developing my first web app with GAE and Python, and it is a lot of fun.
One problem I've been having is exceptions being raised when I don't expect them (since I'm new to web apps). I want to:
Prevent users from ever seeing exceptions
Properly handle exceptions so they don't break my app
Should I put a try/except block around every call to put and get?
What other operations could fail that I should wrap with try/except?
You can create a method called handle_exception on your request handlers to deal with un-expected situations.
The webapp framework will call this automatically when it hits an issue
class YourHandler(webapp.RequestHandler):
def handle_exception(self, exception, mode):
# run the default exception handling
webapp.RequestHandler.handle_exception(self,exception, mode)
# note the error in the log
logging.error("Something bad happend: %s" % str(exception))
# tell your users a friendly message
self.response.out.write("Sorry lovely users, something went wrong")
You can wrap your views in a method that will catch all exceptions, log them and return a handsome 500 error page.
def prevent_error_display(fn):
"""Returns either the original request or 500 error page"""
def wrap(self, *args, **kwargs):
try:
return fn(self, *args, **kwargs)
except Exception, e:
# ... log ...
self.response.set_status(500)
self.response.out.write('Something bad happened back here!')
wrap.__doc__ = fn.__doc__
return wrap
# A sample request handler
class PageHandler(webapp.RequestHandler):
#prevent_error_display
def get(self):
# process your page request