11

Given this simple Bottle code:

def bar(i):
    if i%2 == 0:
        return i
    raise MyError

@route('/foo')
def foo():
    try:
        return bar()
    except MyError as e:
        response.status_code = e.pop('status_code')
        return e

How would one write Bottle middleware so the same exception handling is done implicitly, so that code like this can work identically to above:

@route('/foo')
def foo():
    return bar()
stackoverflowuser95
  • 1,992
  • 3
  • 20
  • 30
  • Could you simply not derive your exception from bottle.HTTPResponse with the exception type then doing the appropriate thing to start with or is the source of your exception not part of your web application and therefore not already dependent on bottle? – Graham Dumpleton Jan 24 '14 at 05:40
  • The exception is being thrown from an independent library; Bottle is only one frontend to it. – stackoverflowuser95 Jan 24 '14 at 05:46
  • 1
    Would a [Bottle plugin](http://bottlepy.org/docs/dev/plugindev.html) suffice? – ron rothman Mar 03 '14 at 17:52

3 Answers3

9

You can do this elegantly with a plugin leveraging abort:

from bottle import abort

def error_translation(func):
    def wrapper(*args,**kwargs):
        try:
            func(*args,**kwargs)
        except ValueError as e:
            abort(400, e.message)
    return wrapper

app.install(error_translation)
micimize
  • 904
  • 9
  • 16
4

Bottle respect the wsgi spec. You can use a classic wsgi middleware

from bottle import route, default_app, run, request

# push an application in the AppStack
default_app.push()


@route('/foo')
def foo():
    raise KeyError()


# error view
@route('/error')
def error():
    return 'Sorry an error occured %(myapp.error)r' % request.environ


# get the bottle application. can be a Bottle() instance too
app = default_app.pop()
app.catchall = False


def error_catcher(environ, start_response):
    # maybe better to fake the start_response callable but this work
    try:
        return app.wsgi(environ, start_response)
    except Exception as e:
        # redirect to the error view if an exception is raised
        environ['PATH_INFO'] = '/error'
        environ['myapp.error'] = e
        return app.wsgi(environ, start_response)


# serve the middleware instead of the applicatio
run(app=error_catcher)
gawel
  • 2,038
  • 14
  • 16
  • Thanks, but is there a way I can show the error output (as JSON) and set the status code; without a redirect? - I'm thinking maybe a lambda in the `error_catcher` block... – stackoverflowuser95 Jan 26 '14 at 07:20
  • It's an internal redirect. And the error view can return some json. error_catcher is a wsgi application so you can do what you want/need. Read more about wsgi application: http://webpython.codepoint.net/wsgi_application_interface – gawel Jan 29 '14 at 10:33
  • So how do I do it without a separate function? - E.g.: a lambda approach? – stackoverflowuser95 Feb 04 '14 at 09:37
1

You can use this instead:

from bottle import error, run, route

@error(500)
def error_handler_500(error):
    return json.dumps({"status": "error", "message": str(error.exception)})

@route("/")
def index():
    a = {}
    a['aaa']

run()
Aminah Nuraini
  • 18,120
  • 8
  • 90
  • 108