Podnieś ostrzeżenie w Pythonie bez przerywania programu

189

Próbuję zgłosić ostrzeżenie w Pythonie bez powodowania awarii / zatrzymania / przerwania programu.

Używam następującej prostej funkcji, aby sprawdzić, czy użytkownik przekazał do niego liczbę niezerową. Jeśli tak, program powinien ich ostrzec, ale kontynuować normalnie. To powinno działać jak poniżej kod, ale należy użyć klasy Warning(), Error()albo Exception()zamiast drukować ostrzeżenie ręcznie.

def is_zero(i):
   if i != 0:
     print "OK"
   else:
     print "WARNING: the input is 0!"
   return i

Jeśli użyję poniższego kodu i przekażę 0 do funkcji, program zawiesza się i wartość nigdy nie jest zwracana. Zamiast tego chcę, aby program działał normalnie i po prostu poinformował użytkownika, że ​​przekazał 0 do funkcji.

def is_zero(i):
   if i != 0:
     print "OK"
   else:
     raise Warning("the input is 0!")
   return i

Chcę mieć możliwość sprawdzenia, czy zostało wysłane ostrzeżenie, testując je przez unittest. Jeśli po prostu wydrukuję wiadomość, nie będę w stanie przetestować jej za pomocą assertRaises in unittest.

Tomas Novotny
źródło
Jak dokładnie chcesz powiadomić użytkownika? przez e-mail lub SMS? ponieważ można to podłączyć, ale musisz być konkretny.
aaronasterling
2
Dlaczego nie wyślesz po prostu printwiadomości?
sje397
1
@ sje397 Chodzi o to, że chcę móc przetestować, czy ostrzeżenie zostało wysłane, testując je przez unittest. Jeśli po prostu wydrukuję wiadomość, nie będę w stanie tego zrobić z assertRaises in unittest.
Tomas Novotny

Odpowiedzi:

157

Nie powinieneś raiseostrzegać, powinieneś używać warningsmodule. Podnosząc go, generujesz błąd, a nie ostrzeżenie.

SilentGhost
źródło
1
Dziękuję Ci bardzo. A w jaki sposób mogę sprawdzić, czy ostrzeżenie zostało rzucone, używając unittest? Nie mogę już używać assertRaises ().
Tomas Novotny
@Tomas Novotny możesz przechwycić stdout i stderr, a następnie sprawdź, czy ciągi wysłane przez ostrzeżenie znajdują się w.
Wheaties
15
@Tomas: Nigdy nie słyszałem o chęci przetestowania pod kątem ostrzeżenia, ale jest dostępny warnings.catch_warningsmenedżer kontekstu, który pozwoli ci to zrobić.
SilentGhost
290
import warnings
warnings.warn("Warning...........Message")

Zobacz dokumentację Pythona: tutaj

nekromanta
źródło
6
I warnings.warn("blabla", DeprecationWarning)za dodanie klasy do rodzaju ostrzeżenia
shadi
52

Domyślnie, w przeciwieństwie do wyjątku, ostrzeżenie nie przerywa.

Następnie podczas generowania ostrzeżenia import warningsmożna określić klasę Warnings . Jeśli nie jest podany, jest on UserWarningdomyślny dosłownie .

>>> warnings.warn('This is a default warning.')
<string>:1: UserWarning: This is a default warning.

Aby zamiast tego po prostu użyć istniejącej klasy, np . DeprecationWarning:

>>> warnings.warn('This is a particular warning.', DeprecationWarning)
<string>:1: DeprecationWarning: This is a particular warning.

Tworzenie niestandardowej klasy ostrzeżeń jest podobne do tworzenia niestandardowej klasy wyjątków:

>>> class MyCustomWarning(UserWarning):
...     pass
... 
... warnings.warn('This is my custom warning.', MyCustomWarning)

<string>:1: MyCustomWarning: This is my custom warning.

Aby przetestować, rozważ assertWarnslub assertWarnsRegex.


Jako alternatywę, szczególnie w przypadku samodzielnych aplikacji, rozważ loggingmoduł. Może rejestrować komunikaty o poziomie debugowania , informacji , ostrzeżenia , błędów , itp. Komunikaty dziennika o poziomie ostrzeżenia lub wyższym są domyślnie drukowane na stderr.

Acumenus
źródło