Don't show Python raise-line in the exception stack
Asked Answered
C

3

26

When I raise my owns exceptions in my Python libraries, the exception stack shows the raise-line itself as the last item of the stack. This is obviously not an error, is conceptually right, but points the focus on something that is not useful for debugging when you're are using code externally, for example as a module.

Is there a way to avoid this and force Python to show the previous-to-last stack item as the last one, like the standard Python libraries.

Chromous answered 12/12, 2010 at 0:27 Comment(6)
The raise line is hidden when it's raised from compiled C code (because there isn't a raise line to show). Python parts of the standard libraries will still show the raise statement in a traceback.Ahl
Perhaps you could hack sys.excepthook to exclude the last line if it's a raise. But generally not possible, get used to it.Importunacy
You could always just raise a useful exception.Unofficial
This would be terrible--of course you want to be able to see where the exception came from! Nothing says that the most interesting frame for an exception is the one right above where it was generated, and the nature of exceptions is that the important part of the stack trace may be anywhere on it, from the block of code generating it all the way up.Third
Note that you can augment exceptions however you want; for example, if you know that the code throwing the exception and two stack frames above it are internal library code, you can assign that to the exception: "e = Exception("error"); e.internal_frames = 3". Then, if you use your own stack reporting code you can check for that attribute in the exception and hide those stack frames by default. You can't do that automatically for other stack formatters, and be sure you have a way to show those stack frames, because at some point you're going to need them.Third
To the people saying this is a terrible idea, I would compare the situation above to exceptions raised by native python functions. They show the exception as coming from the line on which a function was incorrectly used, and not the line in that function that raises the exception. I don't think it is a bad idea in this case, because you can trust that the error isn't coming from a problem within the function itself, because it has been rigorously tested by python's developers. Why not here?Struthious
A
7

Due warning: modifying the behaviour of the interpreter is generally frowned upon. And in any case, seeing exactly where an error was raised may be helpful in debugging, especially if a function can raise an error for several different reasons.

If you use the traceback module, and replace sys.excepthook with a custom function, it's probably possible to do this. But making the change will affect error display for the entire program, not just your module, so is probably not recommended.

You could also look at putting code in try/except blocks, then modifying the error and re-raising it. But your time is probably better spent making unexpected errors unlikely, and writing informative error messages for those that could arise.

Ahl answered 12/12, 2010 at 0:55 Comment(0)
T
5

you can create your own exception hook in python. below is the example of code that i am using.

import sys
import traceback

def exceptionHandler(got_exception_type, got_exception, got_traceback):
    listing  = traceback.format_exception(got_exception_type, got_exception, got_traceback)
    # Removing the listing of statement raise (raise line). 
    del listing[-2]
    filelist = ["org.python.pydev"] # avoiding the debuger modules.
    listing = [ item for item in listing if len([f for f in filelist if f in item]) == 0 ]
    files = [line for line in listing if line.startswith("  File")]
    if len(files) == 1:
        # only one file, remove the header.
        del listing[0]
    print>>sys.stderr, "".join(listing)

And below are some lines that I have used in my custom exception code.

sys.excepthook = exceptionHandler
raise Exception("My Custom error message.")

In the method exception you can add file names or module names in list "filenames" if you want to ignore any unwanted files. As I have ignored the python pydev module since I am using pydev debugger in eclipse.

The above is used in my own module for a specific purpose. you can modify and use it for your modules.

Thundersquall answered 25/11, 2016 at 7:12 Comment(0)
D
-3

I'd suggest to not use the Exception mechanism to validate arguments, as tempting as that is. Coding with exceptions as conditionals is like saying, "crash my app if, as a developer, I don't think of all the bad conditions my provided arguments can cause. Perhaps using exceptions for things not only out of your control but also which is under control of something else like the OS or hardware or the Python language would be more logical, I don't know. In practice however I use exceptions as you request a solution for.

To answer your question, in part, it is just as simple to code thusly:

class MyObject(object):
    def saveas(self, filename):
        if not validate_filename(filename):
            return False
        ...

caller

if not myobject.saveas(filename): report_and_retry()

Perhaps not a great answer, just something to think about.

Darcidarcia answered 12/6, 2015 at 21:11 Comment(2)
I had to upvote this as I'm avoiding as many exceptions as possible and just telling my program to deal with it, step over it, log the issue, and continue walking. I've had more debugging success here than with throwing exceptions everywhere like everyone else does... basically I'm using print() instead of raiseEvolutionist
I've just thought of the other side of this as well, and likely the reason most would downvote on this (I still won't though, as my last comment still stands), most good developers don't just throw exceptions willy nilly for just about every wrong use case, only particular cases that deserve an exception get a raise... granted the above can still happen​ in particular cases not even your code would catch. eg: filename being an object representing a str.Evolutionist

© 2022 - 2024 — McMap. All rights reserved.