web-dev-qa-db-fra.com

Comment déclencher la même exception avec un message personnalisé en Python?

J'ai ce bloc try dans mon code:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise ValueError(errmsg)

À proprement parler, je soulève en fait une autreValueError, pas la ValueError levée par do_something...(), désignée par err dans ce cas. Comment attacher un message personnalisé à err? J'essaie le code suivant mais échoue à cause de err, une ValueError instance , n'étant pas appelable:

try:
    do_something_that_might_raise_an_exception()
except ValueError as err:
    errmsg = 'My custom error message.'
    raise err(errmsg)
97
Kit

Mise à jour: Pour Python 3, vérifiez Réponse de Ben


Pour attacher un message à l'exception actuelle et le relancer: (Le test externe/except est juste pour montrer l'effet)

Pour python 2.x où x> = 6:

try:
    try:
      raise ValueError  # something bad...
    except ValueError as err:
      err.message=err.message+" hello"
      raise              # re-raise current exception
except ValueError as e:
    print(" got error of type "+ str(type(e))+" with message " +e.message)

Cela fera également le bon choix si err est dérivé de ValueError. Par exemple UnicodeDecodeError

Notez que vous pouvez ajouter ce que vous voulez à err. Par exemple err.problematic_array=[1,2,3].


Edit: @Ducan pointe dans un commentaire, ce qui précède ne fonctionne pas avec python 3 car .message n'est pas membre de ValueError. À la place, vous pouvez utiliser ceci (Python 2.6 ou version ultérieure ou 3.x valide):

try:
    try:
      raise ValueError
    except ValueError as err:
       if not err.args: 
           err.args=('',)
       err.args = err.args + ("hello",)
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e.args))

Edit2:

En fonction de l'objectif, vous pouvez également opter pour l'ajout d'informations supplémentaires sous votre propre nom de variable. Pour Python2 et Python3:

try:
    try:
      raise ValueError
    except ValueError as err:
       err.extra_info = "hello"
       raise 
except ValueError as e:
    print(" error was "+ str(type(e))+str(e))
    if 'extra_info' in dir(e):
       print e.extra_info
68
Johan Lundberg

Je me rends compte que cette question existe depuis un certain temps, mais une fois que vous avez la chance de ne supporter que python 3.x, cela devient vraiment une chose de beauté :)

soulever de

Nous pouvons chaîner les exceptions en utilisant raise from .

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

Dans ce cas, l'exception que votre appelant capturerait aurait le numéro de ligne de l'endroit où nous levons notre 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

Notez que l’exception du bas n’a que le stacktrace à partir duquel nous avons levé notre exception. Votre appelant peut toujours obtenir l'exception d'origine en accédant à l'attribut __cause__ de l'exception capturée.

avec_traceback

Ou vous pouvez utiliser with_traceback .

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

À l'aide de ce formulaire, l'exception que votre appelant prendrait a la trace à partir de laquelle l'erreur d'origine s'est produite.

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

Remarquez que l’exception du bas a la ligne sur laquelle nous avons effectué la division non valide ainsi que la ligne sur laquelle nous relançons l’exception.

104
Ben
try:
    try:
        int('a')
    except ValueError as e:
        raise ValueError('There is a problem: {0}'.format(e))
except ValueError as err:
    print err

impressions:

There is a problem: invalid literal for int() with base 10: 'a'
6
eumiro

Il semble que toutes les réponses ajoutent des informations à e.args [0], modifiant ainsi le message d'erreur existant. Y a-t-il un inconvénient à étendre l'argument Tuple à la place? Je pense que l’avantage possible est que vous pouvez laisser le message d’erreur original seul dans les cas où l’analyse de cette chaîne est nécessaire; et vous pouvez ajouter plusieurs éléments au tuple si votre traitement d'erreur personnalisé génère plusieurs messages ou codes d'erreur, dans les cas où le suivi est analysé par programme (comme via un outil de surveillance du système).

## Approach #1, if the exception may not be derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args = (e.args if e.args else Tuple()) + ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

ou

## Approach #2, if the exception is always derived from Exception and well-behaved:

def to_int(x):
    try:
        return int(x)
    except Exception as e:
        e.args += ('Custom message',)
        raise

>>> to_int('12')
12

>>> to_int('12 monkeys')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in to_int
ValueError: ("invalid literal for int() with base 10: '12 monkeys'", 'Custom message')

Pouvez-vous voir un inconvénient à cette approche?

5
Chris Johnson

Ce modèle de code devrait vous permettre de déclencher une exception avec un message personnalisé.

try:
     raise ValueError
except ValueError as err:
    raise type(err)("my message")
2
Ruggero Turra

C'est la fonction que j'utilise pour modifier le message d'exception dans Python 2.7 et 3.x tout en préservant le suivi d'origine. Il nécessite 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)
2
Bryce Guinta

Soit soulever la nouvelle exception avec votre message d'erreur en utilisant

raise Exception('your error message')

ou

raise ValueError('your error message')

à l’endroit où vous voulez le lever OR joindre le message d’erreur (remplacer) à l’exception courante en utilisant 'from':

except ValueError as e:
  raise ValueError('your message') from e
1
Alexey Antonenko

Les exceptions intégrées à Python 3 ont le champ strerror:

except ValueError as err:
  err.strerror = "New error message"
  raise err
1
user3761308

La réponse actuelle ne fonctionne pas bien pour moi. Si l'exception n'est pas capturée à nouveau, le message ajouté ne s'affiche pas.

Cependant, faire comme ci-dessous conserve la trace et affiche le message ajouté, que l'exception soit ou non capturée à nouveau.

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

(J'ai utilisé Python 2.7, je ne l'ai pas essayé dans Python 3)

0
Zitrax