¿Alguna pista sobre cómo lograr esto? ¿Cómo hacerlo tanto en Python 2 como en 3?
Mientras busca documentación para la excepción message atributo Encontré esta pregunta SO, BaseException.message en desuso en Python 2.6, lo que parece indicar que ahora se desaconseja su uso (y por qué no está en los documentos).
– martineau
19 mayo 2011 a las 19:50
lamentablemente, ese enlace ya no parece funcionar.
Aquí hay una muy buena explicación de cuál es el estado del atributo del mensaje y su relación con el atributo args y PEP 352. es del libro gratis Desarrollo de habilidades en Python por Steven F. Lott.
– martineau
7 de mayo de 2014 a las 0:20
cris
En caso de que haya venido aquí buscando una solución para Python 3 el manual dice:
Al generar una nueva excepción (en lugar de usar un simple raise para volver a generar la excepción que se está manejando actualmente), el contexto de excepción implícita se puede complementar con una causa explícita usando from con raise:
raise new_exc from original_exc
Ejemplo:
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
Que se ve así al final:
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.
Convirtiéndose en un totalmente anodino TypeError en un buen mensaje con sugerencias para una solución sin estropear la Excepción original.
Esta es la mejor solución, ya que la excepción resultante apunta a la causa original, proporcione más detalles.
– JT
6 de agosto de 2018 a las 21:28
¿Hay alguna solución para que podamos agregar algún mensaje pero aún así no generar una nueva excepción? Me refiero a simplemente extender el mensaje de la instancia de excepción.
– edcsam
3 de junio de 2020 a las 1:26
Yaa~~ funciona, pero se siente como algo que no se me debe hacer. El mensaje se almacena en e.args, pero eso es una Tupla, por lo que no se puede cambiar. Así que primera copia args en una lista, luego modifíquelo, luego cópielo nuevamente como una Tupla: args = list(e.args)args[0] = 'bar'e.args = tuple(args)
– Chris
3 de junio de 2020 a las 9:58
@edcSam, encontré que esto funciona para una excepción personalizada: def __init__(self, message): super().__init__("some prefix: " + message)
–Kevin
25 de febrero de 2021 a las 21:30
martineau
Lo haría así cambiando su tipo en foo() no requerirá también cambiarlo en bar().
Traceback (most recent call last):
File "test.py", line 13, in <module>
bar('arg1')
File "test.py", line 11, in bar
raise type(e)(e.message + ' happens at %s' % arg1)
IOError: Stuff happens at arg1
Actualización 1
Aquí hay una ligera modificación que conserva el rastreo original:
Traceback (most recent call last):
File "test.py", line 16, in <module>
bar('arg1')
File "test.py", line 11, in bar
foo()
File "test.py", line 5, in foo
raise IOError('Stuff')
IOError: Stuff happens at arg1
Actualización 2
Para Python 3.x, el código de mi primera actualización es sintácticamente incorrecto, además de la idea de tener un message atributo en BaseException estaba retractado en un cambio a PEP 352 el 2012-05-16 (mi primera actualización se publicó el 2012-03-12). Entonces, actualmente, en Python 3.5.2 de todos modos, necesitaría hacer algo en este sentido para preservar el rastreo y no codificar el tipo de excepción en la función bar(). También tenga en cuenta que habrá la línea:
During handling of the above exception, another exception occurred:
en los mensajes de rastreo mostrados.
# for Python 3.x
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e)(str(e) +
' happens at %s' % arg1).with_traceback(sys.exc_info()[2])
bar('arg1')
Actualización 3
Un comentarista preguntó si había alguna forma de que funcionara tanto en Python 2 como en 3. Aunque la respuesta podría parecer “No” debido a las diferencias de sintaxis, hay es una forma de evitar eso mediante el uso de una función de ayuda como reraise() en el six módulo adicional. Entonces, si prefiere no usar la biblioteca por alguna razón, a continuación encontrará una versión independiente simplificada.
Tenga en cuenta también que, dado que la excepción se vuelve a plantear dentro del reraise() función, que aparecerá en cualquier rastreo que se genere, pero el resultado final es lo que desea.
import sys
if sys.version_info.major < 3: # Python 2?
# Using exec avoids a SyntaxError in Python 3.
exec("""def reraise(exc_type, exc_value, exc_traceback=None):
raise exc_type, exc_value, exc_traceback""")
else:
def reraise(exc_type, exc_value, exc_traceback=None):
if exc_value is None:
exc_value = exc_type()
if exc_value.__traceback__ is not exc_traceback:
raise exc_value.with_traceback(exc_traceback)
raise exc_value
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
reraise(type(e), type(e)(str(e) +
' happens at %s' % arg1), sys.exc_info()[2])
bar('arg1')
Eso pierde el backtrace, de alguna manera derrotando el punto de agregar información a una excepción existente. Además, no funciona con excepciones con ctor que toma> 1 argumentos (el tipo es algo que no puede controlar desde el lugar donde detecta la excepción).
– Václav Slavík
12 de marzo de 2012 a las 16:09
@Václav: Es bastante fácil evitar perder el rastro, como se muestra en la actualización que agregué. Si bien esto todavía no maneja todas las excepciones imaginables, funciona para casos similares a los que se muestran en la pregunta del OP.
– martineau
12/03/2012 a las 21:11
esto no es bastante Correcto. Si el tipo (e) anula __str__, puede obtener resultados no deseados. También tenga en cuenta que el segundo argumento se pasa al constructor dado por el primer argumento, lo que produce un algo sin sentido type(e)(type(e)(e.message). En tercer lugar, e.message está en desuso a favor de e.args[0].
– bukzor
11 de diciembre de 2013 a las 23:18
Entonces, ¿no hay una forma portátil que funcione tanto en Python 2 como en 3?
– Elías Dorneles
1 de agosto de 2014 a las 17:09
@martineau ¿Cuál es el propósito de importar dentro del bloque excepto? ¿Es esto para ahorrar memoria importando solo cuando sea necesario?
– AllTradesJack
11 de agosto de 2014 a las 23:54
steve howard
Asumiendo que no quiere o no puede modificar foo(), puede hacer esto:
try:
raise IOError('stuff')
except Exception as e:
if len(e.args) >= 1:
e.args = (e.args[0] + ' happens',) + e.args[1:]
raise
De hecho, esta es la única solución aquí que resuelve el problema en Python 3 sin un mensaje feo y confuso “Durante el manejo de la excepción anterior, ocurrió otra excepción”.
En caso de que la línea de resubida deba agregarse a la traza de la pila, escribir raise e en vez de raise hará el truco.
pero en este caso, si la excepción cambia en foo, también tengo que cambiar la barra, ¿verdad?
– anijhaw
19 mayo 2011 a las 17:56
Si detecta Exception (editado anteriormente), puede detectar cualquier excepción de biblioteca estándar (así como aquellas que heredan de Exception y llaman a Exception.__init__).
–Steve Howard
19 mayo 2011 a las 18:01
para ser más completo/cooperativo, incluya las otras partes de la tupla original: e.args = ('mynewstr' + e.args[0],) + e.args[1:]
– Dubslow
31 de enero de 2018 a las 12:06
@nmz787 Este es el mejor solución para Python 3 de hecho. ¿Cuál es exactamente tu error?
– cristiano
5 de noviembre de 2018 a las 20:27
@Dubslow y martineau Incorporé sus sugerencias en una edición.
– cristiano
5 de noviembre de 2018 a las 20:28
6EQUJ5
No me gustan todas las respuestas dadas hasta ahora. Todavía son demasiado detallados en mi humilde opinión. Tanto en el código como en la salida del mensaje.
Todo lo que quiero tener es el seguimiento de pila que apunte a la excepción de origen, sin cosas de excepción en el medio, por lo que no se deben crear nuevas excepciones, solo volver a generar el original con todas las importante apilar estados de marco en él, que condujo allí.
Steve Howard dio una buena respuesta que quiero extender, no, reducir … solo a python 3.
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
Esto te dará:
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'")
Una simple impresión bonita podría ser algo como
print("\n".join( "-"*i+" "+j for i,j in enumerate(e.args)))
Kee
Un enfoque útil que utilicé es usar el atributo de clase como almacenamiento para los detalles, ya que se puede acceder al atributo de clase tanto desde el objeto de clase como desde la instancia de clase:
class CustomError(Exception):
def __init__(self, details: Dict):
self.details = details
Luego en tu código:
raise CustomError({'data': 5})
Y al detectar un error:
except CustomError as e:
# Do whatever you want with the exception instance
print(e.details)
No es realmente útil ya que el OP solicita que los detalles se impriman como parte del seguimiento de la pila cuando se lanza la excepción original y no se detecta.
– cowbert
31 de julio de 2017 a las 14:24
Creo que la solución es buena. Pero la descripción no es cierta. Los atributos de clase se copian en las instancias cuando las crea. Entonces, cuando modifique el atributo “detalles” de la instancia, el atributo de clase seguirá siendo Ninguno. De todos modos, queremos este comportamiento aquí.
– Adán Wallner
12/09/2019 a las 21:20
Pedro M Duarte
Proporcionaré un fragmento de código que uso a menudo cada vez que quiero agregar información adicional a una excepción. Trabajo tanto en Python 2.7 como en 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))
El código anterior da como resultado el siguiente resultado:
---------------------------------------------------------------------------
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
Sé que esto se desvía un poco del ejemplo proporcionado en la pregunta, pero, sin embargo, espero que alguien lo encuentre útil.
No es realmente útil ya que el OP solicita que los detalles se impriman como parte del seguimiento de la pila cuando se lanza la excepción original y no se detecta.
– cowbert
31 de julio de 2017 a las 14:24
Creo que la solución es buena. Pero la descripción no es cierta. Los atributos de clase se copian en las instancias cuando las crea. Entonces, cuando modifique el atributo “detalles” de la instancia, el atributo de clase seguirá siendo Ninguno. De todos modos, queremos este comportamiento aquí.
– Adán Wallner
12/09/2019 a las 21:20
bukzor
A diferencia de las respuestas anteriores, esto funciona frente a excepciones con muy malas __str__. Eso lo hace Sin embargo, modifique el tipo para eliminar los datos inútiles. __str__ implementaciones.
Todavía me gustaría encontrar una mejora adicional que no modifique el tipo.
from contextlib import contextmanager
@contextmanager
def helpful_info():
try:
yield
except Exception as e:
class CloneException(Exception): pass
CloneException.__name__ = type(e).__name__
CloneException.__module___ = type(e).__module__
helpful_message="%s\n\nhelpful info!" % e
import sys
raise CloneException, helpful_message, sys.exc_traceback
class BadException(Exception):
def __str__(self):
return 'wat.'
with helpful_info():
raise BadException('fooooo')
Se conservan el rastreo original y el tipo (nombre).
Traceback (most recent call last):
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
File "/usr/lib64/python2.6/contextlib.py", line 34, in __exit__
self.gen.throw(type, value, traceback)
File "re_raise.py", line 5, in helpful_info
yield
File "re_raise.py", line 20, in <module>
raise BadException('fooooo')
__main__.BadException: wat.
helpful info!
¿Ha sido útil esta solución?
Tu feedback nos ayuda a saber si la solución es correcta y está funcionando. De esta manera podemos revisar y corregir el contenido.
Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos.
Configurar y más información
Mientras busca documentación para la excepción
message
atributo Encontré esta pregunta SO, BaseException.message en desuso en Python 2.6, lo que parece indicar que ahora se desaconseja su uso (y por qué no está en los documentos).– martineau
19 mayo 2011 a las 19:50
lamentablemente, ese enlace ya no parece funcionar.
–Michael Scott Asato Cuthbert
08/12/2013 a las 20:55
@MichaelScottCuthbert aquí hay una buena alternativa: itmaybeahack.com/book/python-2.6/html/p02/…
– Niels Keurentjes
17 de enero de 2014 a las 16:08
Aquí hay una muy buena explicación de cuál es el estado del atributo del mensaje y su relación con el atributo args y PEP 352. es del libro gratis Desarrollo de habilidades en Python por Steven F. Lott.
– martineau
7 de mayo de 2014 a las 0:20