Adding information to an exception?

前端 未结 9 1784
-上瘾入骨i
-上瘾入骨i 2020-12-02 06:49

I want to achieve something like this:

def foo():
   try:
       raise IOError(\'Stuff \')
   except:
       raise

def bar(arg1):
    try:
       foo()
             


        
相关标签:
9条回答
  • 2020-12-02 07:52

    In case you came here searching for a solution for Python 3 the manual says:

    When raising a new exception (rather than using a bare raise to re-raise the exception currently being handled), the implicit exception context can be supplemented with an explicit cause by using from with raise:

    raise new_exc from original_exc
    

    Example:

    try:
        return [permission() for permission in self.permission_classes]
    except TypeError as e:
        raise TypeError("Make sure your view's 'permission_classes' are iterable. "
                        "If you use '()' to generate a set with a single element "
                        "make sure that there is a comma behind the one (element,).") from e
    

    Which looks like this in the end:

    2017-09-06 16:50:14,797 [ERROR] django.request: Internal Server Error: /v1/sendEmail/
    Traceback (most recent call last):
    File "venv/lib/python3.4/site-packages/rest_framework/views.py", line 275, in get_permissions
        return [permission() for permission in self.permission_classes]
    TypeError: 'type' object is not iterable 
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
        # Traceback removed...
    TypeError: Make sure your view's Permission_classes are iterable. If 
         you use parens () to generate a set with a single element make 
         sure that there is a (comma,) behind the one element.
    

    Turning a totally nondescript TypeError into a nice message with hints towards a solution without messing up the original Exception.

    0 讨论(0)
  • 2020-12-02 07:54

    I don't like all the given answers so far. They are still too verbose imho. In either code and message output.

    All i want to have is the stacktrace pointing to the source exception, no exception stuff in between, so no creation of new exceptions, just re-raising the original with all the relevant stack frame states in it, that led there.

    Steve Howard gave a nice answer which i want to extend, no, reduce ... to python 3 only.

    except Exception as e:
        e.args = ("Some failure state", *e.args)
        raise
    

    The only new thing is the parameter expansion/unpacking which makes it small and easy enough for me to use.

    Try it:

    foo = None
    
    try:
        try:
            state = "bar"
            foo.append(state)
    
        except Exception as e:
            e.args = ("Appending '"+state+"' failed", *e.args)
            raise
    
        print(foo[0]) # would raise too
    
    except Exception as e:
        e.args = ("print(foo) failed: " + str(foo), *e.args)
        raise
    

    This will give you:

    Traceback (most recent call last):
      File "test.py", line 6, in <module>
        foo.append(state)
    AttributeError: ('print(foo) failed: None', "Appending 'bar' failed", "'NoneType' object has no attribute 'append'")
    

    A simple pretty-print could be something like

    print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
    
    0 讨论(0)
  • 2020-12-02 07:55

    I will provide a snippet of code that I use often whenever I want to add extra info to an exception. I works both in Python 2.7 and 3.6.

    import sys
    import traceback
    
    try:
        a = 1
        b = 1j
    
        # The line below raises an exception because
        # we cannot compare int to complex.
        m = max(a, b)  
    
    except Exception as ex:
        # I create my  informational message for debugging:
        msg = "a=%r, b=%r" % (a, b)
    
        # Gather the information from the original exception:
        exc_type, exc_value, exc_traceback = sys.exc_info()
    
        # Format the original exception for a nice printout:
        traceback_string = ''.join(traceback.format_exception(
            exc_type, exc_value, exc_traceback))
    
        # Re-raise a new exception of the same class as the original one, 
        # using my custom message and the original traceback:
        raise type(ex)("%s\n\nORIGINAL TRACEBACK:\n\n%s\n" % (msg, traceback_string))
    

    The code above results in the following output:

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-6-09b74752c60d> in <module>()
         14     raise type(ex)(
         15         "%s\n\nORIGINAL TRACEBACK:\n\n%s\n" %
    ---> 16         (msg, traceback_string))
    
    TypeError: a=1, b=1j
    
    ORIGINAL TRACEBACK:
    
    Traceback (most recent call last):
      File "<ipython-input-6-09b74752c60d>", line 7, in <module>
        m = max(a, b)  # Cannot compare int to complex
    TypeError: no ordering relation is defined for complex numbers
    


    I know this deviates a little from the example provided in the question, but nevertheless I hope someone finds it useful.

    0 讨论(0)
提交回复
热议问题