2012-07-20 7 views
31

Chcę obsługiwać AssertionError s zarówno w celu ukrycia niepotrzebnych części śladu stosu od użytkownika, jak i wydrukowania komunikatu, dlaczego błąd wystąpił i co powinien zrobić użytkownik.Jak radzić sobie z AssertionError w Pythonie i dowiedzieć się, na którym wierszu lub instrukcji wystąpił?

Czy istnieje sposób sprawdzenia, w którym wierszu lub oświadczeniu nie powiodło się assert w bloku except?

try: 
    assert True 
    assert 7 == 7 
    assert 1 == 2 
    # many more statements like this 
except AssertionError: 
    print 'Houston, we have a problem.' 
    print 
    print 'An error occurred on line ???? in statement ???' 
    exit(1) 

nie chcę mieć do tego dodać do każdego rachunku assert:

assert 7 == 7, "7 == 7" 

ponieważ powtarza informacje.

+7

Dwa numery. Po pierwsze, jeśli masz problem ze zidentyfikowaniem wyjątku w 'try..except', to znak, że twój blok' try..except' jest za duży. Po drugie, coś, co powinno zostać złapane przez 'assert', nie jest czymś, co użytkownik powinien kiedykolwiek zobaczyć. Jeśli widzą "AssertionError", właściwym sposobem działania jest skontaktowanie się z programistą i powiedzenie "WTF ?!". –

+2

@John Y, wydajesz się zdezorientowany. Mówisz, że 'AssertionError's nie powinien być widziany przez użytkownika, a następnie, co użytkownik powinien zrobić, gdy widzi jeden. To nie może być jedno i drugie! – devtk

+3

BTW: Asserts powinno dotyczyć struktury twojego kodu, to znaczy, że asercja powinna zawodzić tylko wtedy, gdy masz błąd w swoim oprogramowaniu. Nie powinny być używane do sprawdzania danych wprowadzanych przez użytkownika. Możesz rozważyć użycie innego wyjątku dla tej aplikacji. –

Odpowiedz

47

pomocą modułu traceback:

import sys 
import traceback 

try: 
    assert True 
    assert 7 == 7 
    assert 1 == 2 
    # many more statements like this 
except AssertionError: 
    _, _, tb = sys.exc_info() 
    traceback.print_tb(tb) # Fixed format 
    tb_info = traceback.extract_tb(tb) 
    filename, line, func, text = tb_info[-1] 

    print('An error occurred on line {} in statement {}'.format(line, text)) 
    exit(1) 
1

Moduł ślad błędu i sys.exc_info są przesadą śledzenia źródło wyjątek. To wszystko w domyślnym tracebacku. Więc zamiast wywoływania exit (1) po prostu re-raise:

try: 
    assert "birthday cake" == "ice cream cake", "Should've asked for pie" 
except AssertionError: 
    print 'Houston, we have a problem.' 
    raise 

co daje następujący wynik, który zawiera oświadczenie przestępstwa i numer linia:

Houston, we have a problem. 
Traceback (most recent call last): 
    File "/tmp/poop.py", line 2, in <module> 
    assert "birthday cake" == "ice cream cake", "Should've asked for pie" 
AssertionError: Should've asked for pie 

Podobnie moduł rejestrowania ułatwia zalogować traceback dla dowolnego wyjątku (włączając te, które są przechwytywane i nigdy nie zostały przebudowane):

import logging 

try: 
    assert False == True 
except AssertionError: 
    logging.error("Nothing is real but I can't quit...", exc_info=True)