How do I raise the same Exception with a custom message in Python?

前端 未结 12 1113
情书的邮戳
情书的邮戳 2020-12-12 09:45

I have this try block in my code:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = \'My custom error         


        
相关标签:
12条回答
  • 2020-12-12 10:01

    Python 3 built-in exceptions have the strerror field:

    except ValueError as err:
      err.strerror = "New error message"
      raise err
    
    0 讨论(0)
  • 2020-12-12 10:02

    This only works with Python 3. You can modify the exception's original arguments and add your own arguments.

    An exception remembers the args it was created with. I presume this is so that you can modify the exception.

    In the function reraise we prepend the exception's original arguments with any new arguments that we want (like a message). Finally we re-raise the exception while preserving the trace-back history.

    def reraise(e, *args):
      '''re-raise an exception with extra arguments
      :param e: The exception to reraise
      :param args: Extra args to add to the exception
      '''
    
      # e.args is a tuple of arguments that the exception with instantiated with.
      #
      e.args = args + e.args
    
      # Recreate the expection and preserve the traceback info so thta we can see 
      # where this exception originated.
      #
      raise e.with_traceback(e.__traceback__)   
    
    
    def bad():
      raise ValueError('bad')
    
    def very():
      try:
        bad()
      except Exception as e:
        reraise(e, 'very')
    
    def very_very():
      try:
        very()
      except Exception as e:
        reraise(e, 'very')
    
    very_very()
    

    output

    Traceback (most recent call last):
      File "main.py", line 35, in <module>
        very_very()
      File "main.py", line 30, in very_very
        reraise(e, 'very')
      File "main.py", line 15, in reraise
        raise e.with_traceback(e.__traceback__)
      File "main.py", line 28, in very_very
        very()
      File "main.py", line 24, in very
        reraise(e, 'very')
      File "main.py", line 15, in reraise
        raise e.with_traceback(e.__traceback__)
      File "main.py", line 22, in very
        bad()
      File "main.py", line 18, in bad
        raise ValueError('bad')
    ValueError: ('very', 'very', 'bad')
    
    0 讨论(0)
  • 2020-12-12 10:10

    The current answer did not work good for me, if the exception is not re-caught the appended message is not shown.

    But doing like below both keeps the trace and shows the appended message regardless if the exception is re-caught or not.

    try:
      raise ValueError("Original message")
    except ValueError as err:
      t, v, tb = sys.exc_info()
      raise t, ValueError(err.message + " Appended Info"), tb
    

    ( I used Python 2.7, have not tried it in Python 3 )

    0 讨论(0)
  • 2020-12-12 10:12

    This is the function I use to modify the exception message in Python 2.7 and 3.x while preserving the original traceback. It requires six

    def reraise_modify(caught_exc, append_msg, prepend=False):
        """Append message to exception while preserving attributes.
    
        Preserves exception class, and exception traceback.
    
        Note:
            This function needs to be called inside an except because
            `sys.exc_info()` requires the exception context.
    
        Args:
            caught_exc(Exception): The caught exception object
            append_msg(str): The message to append to the caught exception
            prepend(bool): If True prepend the message to args instead of appending
    
        Returns:
            None
    
        Side Effects:
            Re-raises the exception with the preserved data / trace but
            modified message
        """
        ExceptClass = type(caught_exc)
        # Keep old traceback
        traceback = sys.exc_info()[2]
        if not caught_exc.args:
            # If no args, create our own tuple
            arg_list = [append_msg]
        else:
            # Take the last arg
            # If it is a string
            # append your message.
            # Otherwise append it to the
            # arg list(Not as pretty)
            arg_list = list(caught_exc.args[:-1])
            last_arg = caught_exc.args[-1]
            if isinstance(last_arg, str):
                if prepend:
                    arg_list.append(append_msg + last_arg)
                else:
                    arg_list.append(last_arg + append_msg)
            else:
                arg_list += [last_arg, append_msg]
        caught_exc.args = tuple(arg_list)
        six.reraise(ExceptClass,
                    caught_exc,
                    traceback)
    
    0 讨论(0)
  • 2020-12-12 10:15

    If you're lucky enough to only support python 3.x, this really becomes a thing of beauty :)

    raise from

    We can chain the exceptions using raise from.

    try:
        1 / 0
    except ZeroDivisionError as e:
        raise Exception('Smelly socks') from e
    

    In this case, the exception your caller would catch has the line number of the place where we raise our exception.

    Traceback (most recent call last):
      File "test.py", line 2, in <module>
        1 / 0
    ZeroDivisionError: division by zero
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "test.py", line 4, in <module>
        raise Exception('Smelly socks') from e
    Exception: Smelly socks
    

    Notice the bottom exception only has the stacktrace from where we raised our exception. Your caller could still get the original exception by accessing the __cause__ attribute of the exception they catch.

    with_traceback

    Or you can use with_traceback.

    try:
        1 / 0
    except ZeroDivisionError as e:
        raise Exception('Smelly socks').with_traceback(e.__traceback__)
    

    Using this form, the exception your caller would catch has the traceback from where the original error occurred.

    Traceback (most recent call last):
      File "test.py", line 2, in <module>
        1 / 0
    ZeroDivisionError: division by zero
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "test.py", line 4, in <module>
        raise Exception('Smelly socks').with_traceback(e.__traceback__)
      File "test.py", line 2, in <module>
        1 / 0
    Exception: Smelly socks
    

    Notice the bottom exception has the line where we performed the invalid division as well as the line where we reraise the exception.

    0 讨论(0)
  • 2020-12-12 10:15

    if you want to custom the error type, a simple thing you can do is to define an error class based on ValueError.

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