Musings: Using decorators to reduce duplicate exception handling

Discussion in 'Python' started by J Kenneth King, Feb 17, 2009.

  1. 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. However, this obviously will duplicate code all over the
    place. There are only ever two exceptions that the module itself will
    throw: xmlrpclib.ProtocolError and xmlrpclib.Fault -- both very useful,
    but not show stoppers.

    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):
    """
    A decorator to catch typical xmlrpclib exceptions
    """
    def wrapped(*args, **kwargs):
    try:
    return fn(*args, **kwargs)
    except xmlrpclib.ProtocolError, e:
    print "There was a problem communicating with the server."
    print "URL: %s" % e.url
    print "Headers: %s" % e.headers
    print "Error code: %d" % e.errcode
    print "Error message: %s" % e.errmsg
    print "Please file a report with the TracShell developers."
    pass
    except xmlrpclib.Fault, e:
    print "A fault ocurred"
    print "Fault code: %d" % e.faultCode
    print "Fault string: %s" % e.faultString
    print "If you think this message is the result of an error,"
    print "please file a report with the TracShell developers."
    pass
    return wrapped

    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.

    I was just curious if other Pythonistas out there used the same idea or
    have a better one. Thoughts?
    J Kenneth King, Feb 17, 2009
    #1
    1. Advertising

  2. En Tue, 17 Feb 2009 21:12:57 -0200, J Kenneth King <>
    escribió:

    > 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. However, this obviously will duplicate code all over the
    > place. There are only ever two exceptions that the module itself will
    > throw: xmlrpclib.ProtocolError and xmlrpclib.Fault -- both very useful,
    > but not show stoppers.
    >
    > 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):
    > """
    > A decorator to catch typical xmlrpclib exceptions
    > """
    > def wrapped(*args, **kwargs):
    > try:
    > return fn(*args, **kwargs)
    > except xmlrpclib.ProtocolError, e:
    > print "There was a problem communicating with the server."
    > print "URL: %s" % e.url
    > print "Headers: %s" % e.headers
    > print "Error code: %d" % e.errcode
    > print "Error message: %s" % e.errmsg
    > print "Please file a report with the TracShell developers."
    > pass
    > except xmlrpclib.Fault, e:
    > print "A fault ocurred"
    > print "Fault code: %d" % e.faultCode
    > print "Fault string: %s" % e.faultString
    > print "If you think this message is the result of an error,"
    > print "please file a report with the TracShell developers."
    > pass
    > return wrapped


    I don't like the idea of "hiding" an exception. The caller code doesn't
    know an exception occurred, and just continue doing its work, with bogus
    results... is this what you want? Also, you don't include the stack trace
    - and usually it contains very valuable information. When your users start
    "filing a report with the TracShell developers" and you feel clueless, a
    stack trace is important (you don't have to show it on screen - a log file
    is even better).

    If all you want is to customize the error message, use sys.except_hook

    Looking into the code, those "pass" statement are useless; and error
    messages are usually written to stderr instead of stdout.

    --
    Gabriel Genellina
    Gabriel Genellina, Feb 18, 2009
    #2
    1. Advertising

  3. "Gabriel Genellina" <> writes:

    > En Tue, 17 Feb 2009 21:12:57 -0200, J Kenneth King
    > <> escribió:
    >
    >> 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. However, this obviously will duplicate code all over the
    >> place. There are only ever two exceptions that the module itself will
    >> throw: xmlrpclib.ProtocolError and xmlrpclib.Fault -- both very useful,
    >> but not show stoppers.
    >>
    >> 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):
    >> """
    >> A decorator to catch typical xmlrpclib exceptions
    >> """
    >> def wrapped(*args, **kwargs):
    >> try:
    >> return fn(*args, **kwargs)
    >> except xmlrpclib.ProtocolError, e:
    >> print "There was a problem communicating with the server."
    >> print "URL: %s" % e.url
    >> print "Headers: %s" % e.headers
    >> print "Error code: %d" % e.errcode
    >> print "Error message: %s" % e.errmsg
    >> print "Please file a report with the TracShell developers."
    >> pass
    >> except xmlrpclib.Fault, e:
    >> print "A fault ocurred"
    >> print "Fault code: %d" % e.faultCode
    >> print "Fault string: %s" % e.faultString
    >> print "If you think this message is the result of an error,"
    >> print "please file a report with the TracShell developers."
    >> pass
    >> return wrapped

    >
    > I don't like the idea of "hiding" an exception. The caller code
    > doesn't know an exception occurred, and just continue doing its work,
    > with bogus results... is this what you want? Also, you don't include
    > the stack trace - and usually it contains very valuable
    > information. When your users start "filing a report with the
    > TracShell developers" and you feel clueless, a stack trace is
    > important (you don't have to show it on screen - a log file is even
    > better).
    >
    > If all you want is to customize the error message, use sys.except_hook
    >
    > Looking into the code, those "pass" statement are useless; and error
    > messages are usually written to stderr instead of stdout.


    Thanks for the ideas.

    I haven't actually used this pattern in any projects before, I was just
    looking for a way to reduce the number of common try/except statements I
    needed to have in my code; especially when they all looked exactly the
    same and were catching every single xml-rpc call littered throughout my
    class.

    sys.except_hook looks more like what I was aiming for. I like Lisp's
    "restarts," where I can define error condition handlers in one place
    without having to litter my code with error handling statements.

    Cheers.
    J Kenneth King, Feb 18, 2009
    #3
  4. J Kenneth King schrieb:
    > 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. However, this obviously will duplicate code all over the
    > place. There are only ever two exceptions that the module itself will
    > throw: xmlrpclib.ProtocolError and xmlrpclib.Fault -- both very useful,
    > but not show stoppers.


    I think the answer depends a lot on the actual error handling performed.
    If you want retries, either immediately, or with some larger prologue,
    it might make sense to abstract that away (I would have suggested the
    context-manager thing myself, but Cameron did that already).

    But if you essentially want to abort in all cases, I'd just push the
    handling upwards, and rather improve the error reporting itself, e.g. by
    storing away the trace in a temporary file the user can send you.

    Diez
    Diez B. Roggisch, Feb 22, 2009
    #4
    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:
    334
    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:
    568
    Arien Malec
    Aug 16, 2004
  3. Cameron Simpson
    Replies:
    1
    Views:
    352
    J Kenneth King
    Feb 19, 2009
  4. mk
    Replies:
    2
    Views:
    293
    Terry Reedy
    Nov 24, 2009
  5. Antoine Pitrou

    Re: pointless musings on performance

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

Share This Page