waka-waka-waka
waka-waka-waka

Reputation: 1045

re-raise exception from method as argument

I have a method that needs some wrapping called joule, so I wrap that joule method inside a wrapper called respond (which you will see shortly):

someclass.respond(somemodule.joule(someArgument, someStrategy), 202)

I have a wrapper called respond:

@classmethod
def respond(cls, method, successStatus):
    try:
        method, successStatus

    except Exception as e:
        return {
            'status': 500,
            'message': str(e)
        }

The actual method that gets called and raises an Exception:

def joule(params, strategy):
    try:
        return strategy(params)

    finally:
        session.rollback()
        conn.execute('UNLOCK TABLES')

For some reason, the re-raised exception does not seem to get caught in the respond wrapper! Can you folks help me understand what am I doing incorrectly here?

If this helps, the exception being thrown by sqlalchemy is (please note that this is a scenario being forcibly created to handle the exception correctly):

ProgrammingError: (ProgrammingError) (1146, u"Table 'matrix.vmop_queue' doesn't exist") 'LOCK TABLES vmop_queue WRITE' ()

Upvotes: 1

Views: 61

Answers (1)

b4hand
b4hand

Reputation: 9770

You are misunderstanding how exception handling works. Exception handling operates on the stack frame of called functions.

In the example you give, someclass.respond does not actually invoke somemodule.joule, instead wherever the line that you have written in your example, which is some outer context is the place that receives the uncaught exception. Thus someclass.respond can't possibly handle the exception thrown by somemodule.joule.

There are other ways to achieve what you are trying to accomplish, but I would need more context in order to give you a better suggestion.

To make this a bit more concrete, let's say that foo contains the example line you gave:

def foo():
    someclass.respond(somemodule.joule(someArgument, someStrategy), 202)

You could add the try block to foo to handle the exception thrown by somemodule.joule. This would look like this:

def foo():
    try:
        someclass.respond(somemodule.joule(someArgument, someStrategy), 202)
    except Exception as e:
        pass # do something with the exception here

Alternatively, if the whole purpose for someclass.respond is to handle this exception, then you should move the invocation of somemodule.joule inside of someclass.respond. You could even do this more than one way. You could generically take a function and its arguments, and apply that function to the arguments inside of someclass.respond or you could just directly do the invocation inside of someclass.respond.

Let's take the first approach, since you've said that you don't want to repeat the exception handling. I'll call this new method exception_catcher:

def exception_catcher(func, *args):
    try:
        return func(*args)
    except Exception as e:
        pass # do whatever you want to the exception

Now the foo context will look like this:

def foo():
    exception_catcher(somemodule.joule, someArgument, someStrategy)

Note that exception_catcher is taking somemodule.joule as an argument, and the remaining arguments will be passed to somemodule.joule from within exception_catcher.

Upvotes: 1

Related Questions