Dodawanie informacji do wyjątku?
EDIT: używam Pythona 2.6
Chcę osiągnąć coś takiego:
def foo():
try:
raise IOError('Stuff ')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
e.message = e.message + 'happens at %s' % arg1
raise
bar('arg1')
Traceback...
IOError('Stuff Happens at arg1')
Ale to co dostaję to:
Traceback..
IOError('Stuff')
Jakieś wskazówki, jak to osiągnąć? 8 answers
Zrobiłbym to tak, więc zmiana jego typu w foo()
nie będzie wymagała również zmiany w bar()
.
def foo():
try:
raise IOError('Stuff')
except:
raise
def bar(arg1):
try:
foo()
except Exception as e:
raise type(e)(e.message + ' happens at %s' % arg1)
bar('arg1')
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
Update 1
Oto mała modyfikacja, która zachowuje oryginalny ślad:
...
def bar(arg1):
try:
foo()
except Exception as e:
import sys
raise type(e), type(e)(e.message +
' happens at %s' % arg1), sys.exc_info()[2]
bar('arg1')
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
Update 2
Dla Pythona 3.x, kod w mojej pierwszej aktualizacji jest niepoprawny składniowo plus pomysł posiadania atrybutu message
na BaseException
został wycofany w zmianie NA PEP 352 w dniu 2012-05-16 (moja pierwsza aktualizacja była posted on 2012-03-12). Tak więc obecnie, w Pythonie 3.5.2 tak czy inaczej, musisz zrobić coś w tych liniach, aby zachować traceback, a nie hardcode typu wyjątku w funkcji bar()
. Zauważ również, że będzie linia:
During handling of the above exception, another exception occurred:
W wyświetlanych komunikatach traceback.
# 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')
Update 3
Komentator zapytał, czy istnieje sposób, który będzie działał zarówno w Pythonie 2, jak i 3. Chociaż odpowiedź może wydawać się " nie " ze względu na różnice w składni, tam jest sposobem obejścia tego za pomocą funkcji pomocniczej, takiej jak reraise()
w six
moduł dodatkowy. Jeśli więc z jakiegoś powodu nie chcesz korzystać z biblioteki, poniżej znajduje się uproszczona wersja samodzielna.
Zauważ również, że ponieważ wyjątek jest przekierowywany w funkcji reraise()
, pojawi się on w dowolnym wywołaniu traceback, ale końcowy wynik jest tym, czego chcesz.
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')
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-02 19:09:55
W przypadku, gdy szukasz rozwiązania dla Python3 Instrukcja mówi:
Podczas wywoływania nowego wyjątku (zamiast używania nagiego
raise
do ponownego wywoływania obecnie obsługiwanego wyjątku), kontekst wyjątku implicit może zostać uzupełniony o jawną przyczynę, używając from z raise:
raise new_exc from original_exc
Przykład:
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
Który na końcu wygląda tak:
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.
Zamienianie całkowicie nieopisanego typu w ładną wiadomość z podpowiedziami w kierunku rozwiązania bez zakłócania oryginalnego wyjątku.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 08:06:06
Zakładając, że nie chcesz lub nie możesz modyfikować foo (), możesz spróbować tego:
try:
raise IOError('stuff')
except Exception as e:
e.args = (e.args[0] + ' happens',)
raise
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 18:00:02
Jedną z przydatnych metod, których użyłem, jest użycie atrybutu class jako pamięci dla szczegółów, atrybut klasy jest dostępny zarówno z obiektu klasy, jak I instancji klasy:
class CustomError(Exception):
details = None
Następnie w kodzie:
exc = CustomError('Some message')
exc.details('Details -- add whatever you want')
raise exc
I przy wyłapywaniu błędu:
except CustomError, e:
# Do whatever you want with the exception instance
print e
print e.details
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-11 13:10:32
Możesz zdefiniować własny wyjątek, który dziedziczy od innego i utworzyć własny konstruktor, aby ustawić wartość.
Na przykład:
class MyError(Exception):
def __init__(self, value):
self.value = value
Exception.__init__(self)
def __str__(self):
return repr(self.value)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 17:42:39
W przeciwieństwie do poprzednich odpowiedzi, działa to w obliczu WYJĄTKÓW z naprawdę złym __str__
.
Jest to typ, który może być modyfikowany w celu uwzględnienia nieprzydatnych implementacji __str__
.
Nadal chciałbym znaleźć dodatkowe ulepszenie, które nie modyfikuje typu.
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')
Oryginalny ślad i typ (Nazwa) są zachowane.
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!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-11 23:33:08
Podam fragment kodu, którego używam często, gdy chcę dodać dodatkowe informacje do wyjątku. Pracuję zarówno w Pythonie 2.7 jak i 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))
Powyższy kod daje następujące Wyjście:
---------------------------------------------------------------------------
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
Wiem, że to trochę odbiega od przykładu podanego w pytaniu, ale mimo to mam nadzieję, że ktoś uzna to za przydatne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-21 05:00:32
Maybe
except Exception as e:
raise IOError(e.message + 'happens at %s'%arg1)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 17:42:11