Re: Musings: Using decorators to reduce duplicate exception handling

Discussion in 'Python' started by Cameron Simpson, Feb 18, 2009.

  1. On 17Feb2009 15:12, J Kenneth King <> wrote:
    | I recently started a project called TracShell
    | (http://code.google.com/p/tracshell) where I make heavy use of the
    | xmlrpclib core module.
    |
    | When the number of RPC calls was small, wrapping each call in try/except
    | was acceptable. [...]
    | To combat the duplication, my clever idea was to use a function
    | decorator to wrap any function that used xmlrpclib calls:
    | def catch_errors(fn):
    [...]
    | Maybe I could rename the decorator to something meaningful, but besides
    | that it works pretty well. Now any function I write in my class that
    | uses RPC calls can be wrapped by this decorator and have the exception
    | handling done in a uniform way for these particular exceptions.

    My Python fu is still weak, but I had a similar issue last year and
    wrote a context manager, used thus:

    with NoExceptions(handler):
    ... do stuff that may break ...

    The constructor takes a handleException argument (which may be None, but it
    has to be explicit) to tune which exceptions are caught; default is
    everything. This was for a daemon thread that did RPC calls, so it was
    actually fairly important to never die; normally you'd want to catch only
    specific exceptions.

    Code:

    class NoExceptions(object):
    ''' A context manager to catch _all_ exceptions and log them.
    Arguably this should be a bare try...except but that's syntacticly
    noisy and separates the catch from the top.
    '''

    def __init__(self, handleException):
    ''' Initialise the NoExceptions context manager.
    The handleException is a callable which
    expects (exc_type, exc_value, traceback)
    and returns True or False for the __exit__
    method of the manager.
    If handleException is None, the __exit__ method
    always returns True, suppressing any exception.
    '''
    self.__handler = handleException

    def __enter__(self):
    pass

    def __exit__(self, exc_type, exc_value, traceback):
    if self.__handler is not None:
    return self.__handler(exc_type, exc_value, traceback)
    if exc_type is not None:
    print >>sys.stderr, "ignore %s" % (exc_type,)
    return True

    It doesn't actually solve your duplication issue and is a bit of a niche
    application, but it's a lot shorter than an inline try/except and to my eye
    reads a little better, and it keeps the exception handling up front at the
    calling end where it is visible.

    Cheers,
    --
    Cameron Simpson <> DoD#743
    http://www.cskk.ezoshosting.com/cs/
    Cameron Simpson, Feb 18, 2009
    #1
    1. Advertising

  2. Cameron Simpson <> writes:

    > On 17Feb2009 15:12, J Kenneth King <> wrote:
    > | I recently started a project called TracShell
    > | (http://code.google.com/p/tracshell) where I make heavy use of the
    > | xmlrpclib core module.
    > |
    > | When the number of RPC calls was small, wrapping each call in try/except
    > | was acceptable. [...]
    > | To combat the duplication, my clever idea was to use a function
    > | decorator to wrap any function that used xmlrpclib calls:
    > | def catch_errors(fn):
    > [...]
    > | Maybe I could rename the decorator to something meaningful, but besides
    > | that it works pretty well. Now any function I write in my class that
    > | uses RPC calls can be wrapped by this decorator and have the exception
    > | handling done in a uniform way for these particular exceptions.
    >
    > My Python fu is still weak, but I had a similar issue last year and
    > wrote a context manager, used thus:
    >
    > with NoExceptions(handler):
    > ... do stuff that may break ...
    >
    > The constructor takes a handleException argument (which may be None, but it
    > has to be explicit) to tune which exceptions are caught; default is
    > everything. This was for a daemon thread that did RPC calls, so it was
    > actually fairly important to never die; normally you'd want to catch only
    > specific exceptions.
    >
    > Code:
    >
    > class NoExceptions(object):
    > ''' A context manager to catch _all_ exceptions and log them.
    > Arguably this should be a bare try...except but that's syntacticly
    > noisy and separates the catch from the top.
    > '''
    >
    > def __init__(self, handleException):
    > ''' Initialise the NoExceptions context manager.
    > The handleException is a callable which
    > expects (exc_type, exc_value, traceback)
    > and returns True or False for the __exit__
    > method of the manager.
    > If handleException is None, the __exit__ method
    > always returns True, suppressing any exception.
    > '''
    > self.__handler = handleException
    >
    > def __enter__(self):
    > pass
    >
    > def __exit__(self, exc_type, exc_value, traceback):
    > if self.__handler is not None:
    > return self.__handler(exc_type, exc_value, traceback)
    > if exc_type is not None:
    > print >>sys.stderr, "ignore %s" % (exc_type,)
    > return True
    >
    > It doesn't actually solve your duplication issue and is a bit of a niche
    > application, but it's a lot shorter than an inline try/except and to my eye
    > reads a little better, and it keeps the exception handling up front at the
    > calling end where it is visible.
    >
    > Cheers,


    Ah, that's pretty interesting. I've found a couple other decorator-style
    recipes in the cookbooks online (http://code.activestate.com/recipes/408937/).

    I think you see my point: every single RPC call needs to be caught just
    in case because they are so volatile -- yet you're always looking for
    the exact same exception everywhere... too noisy to have inline
    try/except. I wonder if there are other use cases where Python
    developers have found the need to abstract away repetitive exception
    handling.

    I think this is the first I've seen the newer Python context managers
    being used (though it sneakily looks a lot like what Lisp calls,
    "unwind-protect"). Neat idea.
    J Kenneth King, Feb 19, 2009
    #2
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Martin Andersson

    Is't possible to reduce the text duplicate

    Martin Andersson, Feb 2, 2005, in forum: XML
    Replies:
    0
    Views:
    332
    Martin Andersson
    Feb 2, 2005
  2. Arien Malec

    PEP 318 decorators are not Decorators

    Arien Malec, Aug 13, 2004, in forum: Python
    Replies:
    11
    Views:
    567
    Arien Malec
    Aug 16, 2004
  3. J Kenneth King
    Replies:
    3
    Views:
    354
    Diez B. Roggisch
    Feb 22, 2009
  4. mk
    Replies:
    2
    Views:
    289
    Terry Reedy
    Nov 24, 2009
  5. Antoine Pitrou

    Re: pointless musings on performance

    Antoine Pitrou, Nov 24, 2009, in forum: Python
    Replies:
    9
    Views:
    345
    Paul Boddie
    Nov 26, 2009
Loading...

Share This Page