Print an error message without printing a tracebac

2019-01-26 05:25发布

问题:

I've seen similar questions to this one but none of them really address the trackback. If I have a class like so

class Stop_if_no_then():
    def __init__(self, value one, operator, value_two, then, line_or_label, line_number):
        self._firstvalue = value_one
        self._secondvalue = value_two
        self._operator = operator
        self._gohere = line_or_label
        self._then = then
        self._line_number = line_number

    def execute(self, OtherClass):
        "code comparing the first two values and making changes etc"

What I want my execute method to be able to do is if self._then is not equal to the string "THEN" (in allcaps) then I want it to raise a custom error message and terminate the whole program while also not showing a traceback.

If the error is encountered the only thing that should print out would look something like (I'm using 3 as an example, formatting is not a problem) this.

`Syntax Error (Line 3): No -THEN- present in the statement.`

I'm not very picky about it actually being an exception class object, so there's no issue in that aspect. Since I will be using this in a while loop, simple if, elif just repeats the message over and over (because obviously I am not closing the loop). I have seen sys.exit() but that also prints out a giant block of red text, unless I am not using it correctly. I don't want to catch the exception in my loop because there are other classes in the same module in which I need to implement something like this.

回答1:

You can use a try: and then except Exception as inst: What that will do is give you your error message in a variable named inst and you can print out the arguments on the error with inst.args. Try printing it out and seeing what happens, and is any item in inst.args is the one you are looking for.

EDIT Here is an example I tried with pythons IDLE:

>>> try:
    open("epik.sjj")
except Exception as inst:
    d = inst


>>> d
FileNotFoundError(2, 'No such file or directory')
>>> d.args
(2, 'No such file or directory')
>>> d.args[1]
'No such file or directory'
>>> 

EDIT 2: as for closing the program you can always raise and error or you can use sys.exit()



回答2:

You can turn off the traceback by limiting its depth.

Python 2.x

import sys
sys.tracebacklimit = 0

Python 3.x

In Python 3.5.2 and 3.6.1, setting tracebacklimit to 0 does not seem to have the intended effect. This is a known bug. Note that -1 doesn't work either. Setting it to None does however seem to work, at least for now.

>>> import sys

>>> sys.tracebacklimit = 0
>>> raise Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception

>>> sys.tracebacklimit = -1
>>> raise Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
Exception

>>> sys.tracebacklimit = None
>>> raise Exception
Exception

Nevertheless, for better or worse, if multiple exceptions are raised, they can all still be printed. For example:

socket.gaierror: [Errno -2] Name or service not known

During handling of the above exception, another exception occurred:

urllib.error.URLError: <urlopen error [Errno -2] Name or service not known>


回答3:

The cleanest way that I know is to use sys.excepthook.

You implement a three argument function that accepts type, value, and traceback and does whatever you like (say, only prints the value) and assign that function to sys.excepthook.

Here is an example:

import sys

def excepthook(type, value, traceback):
    print(value)

sys.excepthook = excepthook

raise ValueError('hello')

This is available in both python 2 and python 3.



回答4:

In general, if you want to catch any exception except SystemExit, and exit with the exception's message without the traceback, define your main function as below:

>>> import sys

>>> def main():
...     try:
...         # Run your program from here.
...         raise RandomException  # For testing
...     except (Exception, KeyboardInterrupt) as exc:
...         sys.exit(exc)
... 
>>> main()
name 'RandomException' is not defined

$ echo $?
1

Note that in the case of multiple exceptions being raised, only one message is printed.

This answer is meant to improve upon the one by The-IT.



回答5:

If you want to get rid of any traceback for customs exceptions and have line number, you can do this trick

Python 3

import sys
import inspect

class NoTraceBackWithLineNumber(Exception):
    def __init__(self, msg):
        try:
            ln = sys.exc_info()[-1].tb_lineno
        except AttributeError:
            ln = inspect.currentframe().f_back.f_lineno
        self.args = "{0.__name__} (line {1}): {2}".format(type(self), ln, msg),
        sys.exit(self)

class MyNewError(NoTraceBackWithLineNumber):
    pass

raise MyNewError("Now TraceBack Is Gone")

Will give this output, and make the raise keyword useless

MyNewError (line 16): Now TraceBack Is Gone